From 5e93f35209578fcabfa855e427354195e54b491f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:38 -0500 Subject: staging: r8723au: Add source files for new driver - part 1 The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets. A driver for it has been available in a GitHub repo for several months. This commit contains the first part of the source files. The source is arbitrarily split to avoid E-mail files that are too large. Jes Sorensen at RedHat has made many improvements to the vendor code, and he has been doing the testing. I do not have access to this device. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/core/rtw_ap.c | 2087 +++++ drivers/staging/rtl8723au/core/rtw_cmd.c | 1874 +++++ drivers/staging/rtl8723au/core/rtw_efuse.c | 718 ++ drivers/staging/rtl8723au/core/rtw_ieee80211.c | 1861 +++++ drivers/staging/rtl8723au/core/rtw_io.c | 266 + drivers/staging/rtl8723au/core/rtw_ioctl_set.c | 601 ++ drivers/staging/rtl8723au/core/rtw_led.c | 1899 +++++ drivers/staging/rtl8723au/core/rtw_mlme.c | 2499 ++++++ drivers/staging/rtl8723au/core/rtw_mlme_ext.c | 9988 ++++++++++++++++++++++++ drivers/staging/rtl8723au/core/rtw_p2p.c | 3963 ++++++++++ drivers/staging/rtl8723au/core/rtw_pwrctrl.c | 686 ++ drivers/staging/rtl8723au/core/rtw_recv.c | 2471 ++++++ drivers/staging/rtl8723au/core/rtw_security.c | 1653 ++++ drivers/staging/rtl8723au/core/rtw_sreset.c | 253 + drivers/staging/rtl8723au/core/rtw_sta_mgt.c | 509 ++ drivers/staging/rtl8723au/core/rtw_wlan_util.c | 1760 +++++ drivers/staging/rtl8723au/core/rtw_xmit.c | 2463 ++++++ 17 files changed, 35551 insertions(+) create mode 100644 drivers/staging/rtl8723au/core/rtw_ap.c create mode 100644 drivers/staging/rtl8723au/core/rtw_cmd.c create mode 100644 drivers/staging/rtl8723au/core/rtw_efuse.c create mode 100644 drivers/staging/rtl8723au/core/rtw_ieee80211.c create mode 100644 drivers/staging/rtl8723au/core/rtw_io.c create mode 100644 drivers/staging/rtl8723au/core/rtw_ioctl_set.c create mode 100644 drivers/staging/rtl8723au/core/rtw_led.c create mode 100644 drivers/staging/rtl8723au/core/rtw_mlme.c create mode 100644 drivers/staging/rtl8723au/core/rtw_mlme_ext.c create mode 100644 drivers/staging/rtl8723au/core/rtw_p2p.c create mode 100644 drivers/staging/rtl8723au/core/rtw_pwrctrl.c create mode 100644 drivers/staging/rtl8723au/core/rtw_recv.c create mode 100644 drivers/staging/rtl8723au/core/rtw_security.c create mode 100644 drivers/staging/rtl8723au/core/rtw_sreset.c create mode 100644 drivers/staging/rtl8723au/core/rtw_sta_mgt.c create mode 100644 drivers/staging/rtl8723au/core/rtw_wlan_util.c create mode 100644 drivers/staging/rtl8723au/core/rtw_xmit.c (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c new file mode 100644 index 000000000000..3d936eb937ef --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_ap.c @@ -0,0 +1,2087 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_AP_C_ + +#include +#include +#include +#include + +#ifdef CONFIG_8723AU_AP_MODE + +extern unsigned char RTW_WPA_OUI23A[]; +extern unsigned char WMM_OUI23A[]; +extern unsigned char WPS_OUI23A[]; +extern unsigned char P2P_OUI23A[]; +extern unsigned char WFD_OUI23A[]; + +void init_mlme_ap_info23a(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + + spin_lock_init(&pmlmepriv->bcn_update_lock); + + /* for ACL */ + _rtw_init_queue23a(&pacl_list->acl_node_q); + + start_ap_mode23a(padapter); +} + +void free_mlme_ap_info23a(struct rtw_adapter *padapter) +{ + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + pmlmepriv->update_bcn = false; + pmlmeext->bstart_bss = false; + + rtw_sta_flush23a(padapter); + + pmlmeinfo->state = _HW_STATE_NOLINK_; + + /* free_assoc_sta_resources */ + rtw_free_all_stainfo23a(padapter); + + /* free bc/mc sta_info */ + psta = rtw_get_bcmc_stainfo23a(padapter); + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(padapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); +} + +static void update_BCNTIM(struct rtw_adapter *padapter) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; + unsigned char *pie = pnetwork_mlmeext->IEs; + u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; + u16 tim_bitmap_le; + uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; + + tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); + + p = rtw_get_ie23a(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); + if (p != NULL && tim_ielen>0) { + tim_ielen += 2; + + premainder_ie = p+tim_ielen; + + tim_ie_offset = (int)(p -pie); + + remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; + + /* append TIM IE from dst_ie offset */ + dst_ie = p; + } else { + tim_ielen = 0; + + /* calulate head_len */ + offset = _FIXED_IE_LENGTH_; + + /* get ssid_ie len */ + p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + if (p != NULL) + offset += tmp_len+2; + + /* get supported rates len */ + p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + if (p != NULL) + offset += tmp_len+2; + + /* DS Parameter Set IE, len = 3 */ + offset += 3; + + premainder_ie = pie + offset; + + remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; + + /* append TIM IE from offset */ + dst_ie = pie + offset; + } + + if (remainder_ielen > 0) { + pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC); + if (pbackup_remainder_ie && premainder_ie) + memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); + } + + *dst_ie++= _TIM_IE_; + + if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc)) + tim_ielen = 5; + else + tim_ielen = 4; + + *dst_ie++= tim_ielen; + + *dst_ie++= 0;/* DTIM count */ + *dst_ie++= 1;/* DTIM peroid */ + + if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */ + *dst_ie++ = BIT(0);/* bitmap ctrl */ + else + *dst_ie++ = 0; + + if (tim_ielen == 4) { + *dst_ie++ = *(u8*)&tim_bitmap_le; + } else if (tim_ielen == 5) { + memcpy(dst_ie, &tim_bitmap_le, 2); + dst_ie+= 2; + } + + /* copy remainder IE */ + if (pbackup_remainder_ie) { + memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); + + kfree(pbackup_remainder_ie); + } + + offset = (uint)(dst_ie - pie); + pnetwork_mlmeext->IELength = offset + remainder_ielen; + + set_tx_beacon_cmd23a(padapter); +} + +static u8 chk_sta_is_alive(struct sta_info *psta) +{ + u8 ret = false; + + if ((psta->sta_stats.last_rx_data_pkts + + psta->sta_stats.last_rx_ctrl_pkts) != + (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) + ret = true; + + sta_update_last_rx_pkts(psta); + + return ret; +} + +void expire_timeout_chk23a(struct rtw_adapter *padapter) +{ + struct list_head *phead, *plist, *ptmp; + u8 updated = 0; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 chk_alive_num = 0; + char chk_alive_list[NUM_STA]; + int i; + + spin_lock_bh(&pstapriv->auth_list_lock); + + phead = &pstapriv->auth_list; + + /* check auth_queue */ + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, auth_list); + + if (psta->expire_to>0) { + psta->expire_to--; + if (psta->expire_to == 0) { + list_del_init(&psta->auth_list); + pstapriv->auth_list_cnt--; + + DBG_8723A("auth expire %pM\n", psta->hwaddr); + + spin_unlock_bh(&pstapriv->auth_list_lock); + + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(padapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + + spin_lock_bh(&pstapriv->auth_list_lock); + } + } + + } + + spin_unlock_bh(&pstapriv->auth_list_lock); + + spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + + /* check asoc_queue */ + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + if (chk_sta_is_alive(psta) || !psta->expire_to) { + psta->expire_to = pstapriv->expire_to; + psta->keep_alive_trycnt = 0; + } else { + psta->expire_to--; + } + + if (psta->expire_to <= 0) + { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (padapter->registrypriv.wifi_spec == 1) + { + psta->expire_to = pstapriv->expire_to; + continue; + } + + if (psta->state & WIFI_SLEEP_STATE) { + if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { + /* to check if alive by another methods if staion is at ps mode. */ + psta->expire_to = pstapriv->expire_to; + psta->state |= WIFI_STA_ALIVE_CHK_STATE; + + /* to update bcn with tim_bitmap for this station */ + pstapriv->tim_bitmap |= CHKBIT(psta->aid); + update_beacon23a(padapter, _TIM_IE_, NULL, false); + + if (!pmlmeext->active_keep_alive_check) + continue; + } + } + + if (pmlmeext->active_keep_alive_check) { + int stainfo_offset; + + stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) { + chk_alive_list[chk_alive_num++] = stainfo_offset; + } + + continue; + } + + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + + DBG_8723A("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state); + updated = ap_free_sta23a(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); + } else { + /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ + if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) + && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME/pstapriv->asoc_list_cnt)/2) + ) { + DBG_8723A("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__, + MAC_ARG(psta->hwaddr), + psta->sleepq_len, + padapter->xmitpriv.free_xmitframe_cnt, + pstapriv->asoc_list_cnt); + wakeup_sta_to_xmit23a(padapter, psta); + } + } + } + + spin_unlock_bh(&pstapriv->asoc_list_lock); + + if (chk_alive_num) { + + u8 backup_oper_channel = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + /* switch to correct channel of current network before issue keep-alive frames */ + if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel) { + backup_oper_channel = rtw_get_oper_ch23a(padapter); + SelectChannel23a(padapter, pmlmeext->cur_channel); + } + + /* issue null data to check sta alive*/ + for (i = 0; i < chk_alive_num; i++) { + + int ret = _FAIL; + + psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]); + if (!(psta->state &_FW_LINKED)) + continue; + + if (psta->state & WIFI_SLEEP_STATE) + ret = issue_nulldata23a(padapter, psta->hwaddr, 0, 1, 50); + else + ret = issue_nulldata23a(padapter, psta->hwaddr, 0, 3, 50); + + psta->keep_alive_trycnt++; + if (ret == _SUCCESS) + { + DBG_8723A("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr)); + psta->expire_to = pstapriv->expire_to; + psta->keep_alive_trycnt = 0; + continue; + } + else if (psta->keep_alive_trycnt <= 3) + { + DBG_8723A("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt); + psta->expire_to = 1; + continue; + } + + psta->keep_alive_trycnt = 0; + + DBG_8723A("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state); + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&psta->asoc_list)) { + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta23a(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + } + + if (backup_oper_channel>0) /* back to the original operation channel */ + SelectChannel23a(padapter, backup_oper_channel); +} + + associated_clients_update23a(padapter, updated); +} + +void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_level) +{ + int i; + u8 rf_type; + u32 init_rate = 0; + unsigned char sta_band = 0, raid, shortGIrate = false; + unsigned char limit; + unsigned int tx_ra_bitmap = 0; + struct ht_priv *psta_ht = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + + if (psta) + psta_ht = &psta->htpriv; + else + return; + + if (!(psta->state & _FW_LINKED)) + return; + + /* b/g mode ra_bitmap */ + for (i = 0; ibssrateset); i++) + { + if (psta->bssrateset[i]) + tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value23a(psta->bssrateset[i]&0x7f); + } + /* n mode ra_bitmap */ + if (psta_ht->ht_option) + { + rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + if (rf_type == RF_2T2R) + limit = 16;/* 2R */ + else + limit = 8;/* 1R */ + + for (i = 0; iht_cap.mcs.rx_mask[i/8] & BIT(i%8)) + tx_ra_bitmap |= CHKBIT(i+12); + } + + /* max short GI rate */ + shortGIrate = psta_ht->sgi; + } + + if (pcur_network->Configuration.DSConfig > 14) { + /* 5G band */ + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_5N | WIRELESS_11A; + else + sta_band |= WIRELESS_11A; + } else { + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B; + else if (tx_ra_bitmap & 0xff0) + sta_band |= WIRELESS_11G |WIRELESS_11B; + else + sta_band |= WIRELESS_11B; + } + + psta->wireless_mode = sta_band; + + raid = networktype_to_raid23a(sta_band); + init_rate = get_highest_rate_idx23a(tx_ra_bitmap&0x0fffffff)&0x3f; + + if (psta->aid < NUM_STA) + { + u8 arg = 0; + + arg = psta->mac_id&0x1f; + + arg |= BIT(7);/* support entry 2~31 */ + + if (shortGIrate == true) + arg |= BIT(5); + + tx_ra_bitmap |= ((raid<<28)&0xf0000000); + + DBG_8723A("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = " + "0x%x\n", + __func__, psta->mac_id, raid, tx_ra_bitmap, arg); + + /* bitmap[0:27] = tx_rate_bitmap */ + /* bitmap[28:31]= Rate Adaptive id */ + /* arg[0:4] = macid */ + /* arg[5] = Short GI */ + rtw_hal_add_ra_tid23a(padapter, tx_ra_bitmap, arg, rssi_level); + + if (shortGIrate == true) + init_rate |= BIT(6); + + /* set ra_id, init_rate */ + psta->raid = raid; + psta->init_rate = init_rate; + + } + else + { + DBG_8723A("station aid %d exceed the max number\n", psta->aid); + } +} + +static void update_bmc_sta(struct rtw_adapter *padapter) +{ + u32 init_rate = 0; + unsigned char network_type, raid; + int i, supportRateNum = 0; + unsigned int tx_ra_bitmap = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + struct sta_info *psta = rtw_get_bcmc_stainfo23a(padapter); + + if (psta) + { + psta->aid = 0;/* default set to 0 */ + psta->mac_id = psta->aid + 1; + + psta->qos_option = 0; + psta->htpriv.ht_option = false; + + psta->ieee8021x_blocked = 0; + + memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); + + /* prepare for add_RATid23a */ + supportRateNum = rtw_get_rateset_len23a((u8*)&pcur_network->SupportedRates); + network_type = rtw_check_network_type23a((u8*)&pcur_network->SupportedRates, supportRateNum, 1); + + memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum); + psta->bssratelen = supportRateNum; + + /* b/g mode ra_bitmap */ + for (i = 0; ibssrateset[i]) + tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value23a(psta->bssrateset[i]&0x7f); + } + + if (pcur_network->Configuration.DSConfig > 14) { + /* force to A mode. 5G doesn't support CCK rates */ + network_type = WIRELESS_11A; + tx_ra_bitmap = 0x150; /* 6, 12, 24 Mbps */ + } else { + /* force to b mode */ + network_type = WIRELESS_11B; + tx_ra_bitmap = 0xf; + } + + raid = networktype_to_raid23a(network_type); + init_rate = get_highest_rate_idx23a(tx_ra_bitmap&0x0fffffff)&0x3f; + + /* ap mode */ + rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true); + + { + u8 arg = 0; + + arg = psta->mac_id&0x1f; + + arg |= BIT(7); + + tx_ra_bitmap |= ((raid<<28)&0xf0000000); + + DBG_8723A("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg); + + /* bitmap[0:27] = tx_rate_bitmap */ + /* bitmap[28:31]= Rate Adaptive id */ + /* arg[0:4] = macid */ + /* arg[5] = Short GI */ + rtw_hal_add_ra_tid23a(padapter, tx_ra_bitmap, arg, 0); + + } + + /* set ra_id, init_rate */ + psta->raid = raid; + psta->init_rate = init_rate; + + rtw_stassoc_hw_rpt23a(padapter, psta); + + spin_lock_bh(&psta->lock); + psta->state = _FW_LINKED; + spin_unlock_bh(&psta->lock); + + } + else + { + DBG_8723A("add_RATid23a_bmc_sta error!\n"); + } +} + +/* notes: */ +/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */ +/* MAC_ID = AID+1 for sta in ap/adhoc mode */ +/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */ +/* MAC_ID = 0 for bssid for sta/ap/adhoc */ +/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ + +void update_sta_info23a_apmode23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; + struct ht_priv *phtpriv_sta = &psta->htpriv; + /* set intf_tag to if1 */ + + psta->mac_id = psta->aid+1; + DBG_8723A("%s\n", __func__); + + /* ap mode */ + rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true); + + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) + psta->ieee8021x_blocked = true; + else + psta->ieee8021x_blocked = false; + + /* update sta's cap */ + + /* ERP */ + VCS_update23a(padapter, psta); + /* HT related cap */ + if (phtpriv_sta->ht_option) + { + /* check if sta supports rx ampdu */ + phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; + + /* check if sta support s Short GI */ + if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) + phtpriv_sta->sgi = true; + + /* bwmode */ + if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40)) { + /* phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_40; */ + phtpriv_sta->bwmode = pmlmeext->cur_bwmode; + phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; + + } + + psta->qos_option = true; + + } + else + { + phtpriv_sta->ampdu_enable = false; + + phtpriv_sta->sgi = false; + phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; + phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + /* Rx AMPDU */ + send_delba23a(padapter, 0, psta->hwaddr);/* recipient */ + + /* TX AMPDU */ + send_delba23a(padapter, 1, psta->hwaddr);/* originator */ + phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */ + phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */ + + /* todo: init other variables */ + + memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); + + spin_lock_bh(&psta->lock); + psta->state |= _FW_LINKED; + spin_unlock_bh(&psta->lock); +} + +static void update_hw_ht_param(struct rtw_adapter *padapter) +{ + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + DBG_8723A("%s\n", __func__); + + /* handle A-MPDU parameter field */ + /* + AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + AMPDU_para [4:2]:Min MPDU Start Spacing + */ + max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + + /* Config SM Power Save setting */ + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) + DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); +} + +static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf) +{ + u8 *p; + u8 val8, cur_channel, cur_bwmode, cur_ch_offset; + u16 bcn_interval; + u32 acparm; + int ie_len; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv* psecuritypriv = &padapter->securitypriv; + struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; + struct HT_info_element *pht_info = NULL; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; + cur_channel = pnetwork->Configuration.DSConfig; + cur_bwmode = HT_CHANNEL_WIDTH_20;; + cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + /* check if there is wps ie, */ + /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */ + /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */ + if (NULL == rtw_get_wps_ie23a(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL)) + pmlmeext->bstart_bss = true; + + /* todo: update wmm, ht cap */ + /* pmlmeinfo->WMM_enable; */ + /* pmlmeinfo->HT_enable; */ + if (pmlmepriv->qospriv.qos_option) + pmlmeinfo->WMM_enable = true; + if (pmlmepriv->htpriv.ht_option) { + pmlmeinfo->WMM_enable = true; + pmlmeinfo->HT_enable = true; + + update_hw_ht_param(padapter); + } + + if (pmlmepriv->cur_network.join_res != true) { + /* setting only at first time */ + /* WEP Key will be set before this function, do not clear CAM. */ + if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) + flush_all_cam_entry23a(padapter); /* clear CAM */ + } + + /* set MSR to AP_Mode */ + Set_MSR23a(padapter, _HW_STATE_AP_); + + /* Set BSSID REG */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pnetwork->MacAddress); + + /* Set EDCA param reg */ + acparm = 0x002F3217; /* VO */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); + acparm = 0x005E4317; /* VI */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); + acparm = 0x005ea42b; + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + acparm = 0x0000A444; /* BK */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); + + /* Set Security */ + val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; + rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + /* Beacon Control related register */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); + + UpdateBrateTbl23a(padapter, pnetwork->SupportedRates); + rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); + + if (!pmlmepriv->cur_network.join_res) { + /* setting only at first time */ + + /* disable dynamic functions, such as high power, DIG */ + + /* turn on all dynamic functions */ + Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); + } + /* set channel, bwmode */ + p = rtw_get_ie23a((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ies)), + _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - + sizeof(struct ndis_802_11_fixed_ies))); + if (p && ie_len) { + pht_info = (struct HT_info_element *)(p+2); + + if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { + /* switch to the 40M Hz mode */ + cur_bwmode = HT_CHANNEL_WIDTH_40; + switch (pht_info->infos[0] & 0x3) { + case 1: + /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; */ + cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + case 3: + cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + default: + cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } + } + /* TODO: need to judge the phy parameters on concurrent mode for single phy */ + set_channel_bwmode23a(padapter, cur_channel, cur_ch_offset, cur_bwmode); + + DBG_8723A("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, + cur_ch_offset); + + pmlmeext->cur_channel = cur_channel; + pmlmeext->cur_bwmode = cur_bwmode; + pmlmeext->cur_ch_offset = cur_ch_offset; + pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type; + + /* update cur_wireless_mode */ + update_wireless_mode23a(padapter); + + /* udpate capability after cur_wireless_mode updated */ + update_capinfo23a(padapter, rtw_get_capability23a((struct wlan_bssid_ex *)pnetwork)); + + /* let pnetwork_mlmeext == pnetwork_mlme. */ + memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); + +#ifdef CONFIG_8723AU_P2P + memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.ssid, + pnetwork->Ssid.ssid_len); + pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.ssid_len; +#endif /* CONFIG_8723AU_P2P */ + + if (pmlmeext->bstart_bss) { + update_beacon23a(padapter, _TIM_IE_, NULL, false); + + /* issue beacon frame */ + if (send_beacon23a(padapter) == _FAIL) + DBG_8723A("issue_beacon23a, fail!\n"); + } + + /* update bc/mc sta_info */ + update_bmc_sta(padapter); +} + +int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) +{ + int ret = _SUCCESS; + u8 *p; + u8 *pHT_caps_ie = NULL; + u8 *pHT_info_ie = NULL; + struct sta_info *psta = NULL; + u16 cap, ht_cap = false; + uint ie_len = 0; + int group_cipher, pairwise_cipher; + u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; + int supportRateNum = 0; + u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; + u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *pbss_network = &pmlmepriv->cur_network.network; + u8 *ie = pbss_network->IEs; + + /* SSID */ + /* Supported rates */ + /* DS Params */ + /* WLAN_EID_COUNTRY */ + /* ERP Information element */ + /* Extended supported rates */ + /* WPA/WPA2 */ + /* Wi-Fi Wireless Multimedia Extensions */ + /* ht_capab, ht_oper */ + /* WPS IE */ + + DBG_8723A("%s, len =%d\n", __func__, len); + + if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) + return _FAIL; + + if (len>MAX_IE_SZ) + return _FAIL; + + pbss_network->IELength = len; + + memset(ie, 0, MAX_IE_SZ); + + memcpy(ie, pbuf, pbss_network->IELength); + + if (pbss_network->InfrastructureMode!= Ndis802_11APMode) + return _FAIL; + + pbss_network->Rssi = 0; + + memcpy(pbss_network->MacAddress, myid(&padapter->eeprompriv), ETH_ALEN); + + /* beacon interval */ + /* ie + 8; 8: TimeStamp, 2: Beacon Interval 2:Capability */ + p = rtw_get_beacon_interval23a_from_ie(ie); + pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p); + + /* capability */ + cap = RTW_GET_LE16(ie); + + /* SSID */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, + (pbss_network->IELength -_BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + memset(&pbss_network->Ssid, 0, sizeof(struct cfg80211_ssid)); + memcpy(pbss_network->Ssid.ssid, (p + 2), ie_len); + pbss_network->Ssid.ssid_len = ie_len; + } + + /* chnnel */ + channel = 0; + pbss_network->Configuration.Length = 0; + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + channel = *(p + 2); + + pbss_network->Configuration.DSConfig = channel; + + memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); + /* get supported rates */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p) { + memcpy(supportRate, p+2, ie_len); + supportRateNum = ie_len; + } + + /* get ext_supported rates */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, + &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); + if (p) { + memcpy(supportRate+supportRateNum, p+2, ie_len); + supportRateNum += ie_len; + } + + network_type = rtw_check_network_type23a(supportRate, + supportRateNum, channel); + + rtw_set_supported_rate23a(pbss_network->SupportedRates, network_type); + + /* parsing ERP_IE */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + ERP_IE_handler23a(padapter, (struct ndis_802_11_var_ies *)p); + + /* update privacy/security */ + if (cap & BIT(4)) + pbss_network->Privacy = 1; + else + pbss_network->Privacy = 0; + + psecuritypriv->wpa_psk = 0; + + /* wpa2 */ + group_cipher = 0; pairwise_cipher = 0; + psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; + psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + if (rtw_parse_wpa2_ie23a(p, ie_len+2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + + psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ + psecuritypriv->wpa_psk |= BIT(1); + + psecuritypriv->wpa2_group_cipher = group_cipher; + psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; + } + } + + /* wpa */ + ie_len = 0; + group_cipher = 0; + pairwise_cipher = 0; + psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; + psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; + for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) { + p = rtw_get_ie23a(p, _SSN_IE_1_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_ - + (ie_len + 2))); + if ((p) && (!memcmp(p+2, OUI1, 4))) { + if (rtw_parse_wpa_ie23a(p, ie_len+2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + + /* psk, todo:802.1x */ + psecuritypriv->dot8021xalg = 1; + + psecuritypriv->wpa_psk |= BIT(0); + + psecuritypriv->wpa_group_cipher = group_cipher; + psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; + } + break; + } + + if ((p == NULL) || (ie_len == 0)) + break; + } + + /* wmm */ + ie_len = 0; + pmlmepriv->qospriv.qos_option = 0; + if (pregistrypriv->wmm_enable) { + for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) { + p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len, + (pbss_network->IELength - + _BEACON_IE_OFFSET_ - (ie_len + 2))); + if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) { + pmlmepriv->qospriv.qos_option = 1; + + *(p+8) |= BIT(7);/* QoS Info, support U-APSD */ + + /* disable all ACM bits since the WMM admission + * control is not supported + */ + *(p + 10) &= ~BIT(4); /* BE */ + *(p + 14) &= ~BIT(4); /* BK */ + *(p + 18) &= ~BIT(4); /* VI */ + *(p + 22) &= ~BIT(4); /* VO */ + break; + } + if ((p == NULL) || (ie_len == 0)) + break; + } + } + /* parsing HT_CAP_IE */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + u8 rf_type; + + struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p+2); + + pHT_caps_ie = p; + + ht_cap = true; + network_type |= WIRELESS_11_24N; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + + if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || + (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) + pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (0x07<<2)); + else + pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY&0x00); + + /* set Max Rx AMPDU size to 64K */ + pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_FACTOR & 0x03); + + if (rf_type == RF_1T1R) { + pht_cap->mcs.rx_mask[0] = 0xff; + pht_cap->mcs.rx_mask[1] = 0x0; + } + + memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len); + } + + /* parsing HT_INFO_IE */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, + (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + pHT_info_ie = p; + + switch (network_type) { + case WIRELESS_11B: + pbss_network->NetworkTypeInUse = Ndis802_11DS; + break; + case WIRELESS_11G: + case WIRELESS_11BG: + case WIRELESS_11G_24N: + case WIRELESS_11BG_24N: + pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + case WIRELESS_11A: + pbss_network->NetworkTypeInUse = Ndis802_11OFDM5; + break; + default : + pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + } + + pmlmepriv->cur_network.network_type = network_type; + + pmlmepriv->htpriv.ht_option = false; + + /* ht_cap */ + if (pregistrypriv->ht_enable && ht_cap) { + pmlmepriv->htpriv.ht_option = true; + pmlmepriv->qospriv.qos_option = 1; + + if (pregistrypriv->ampdu_enable == 1) + pmlmepriv->htpriv.ampdu_enable = true; + + HT_caps_handler23a(padapter, (struct ndis_802_11_var_ies *)pHT_caps_ie); + + HT_info_handler23a(padapter, (struct ndis_802_11_var_ies *)pHT_info_ie); + } + + pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network); + + /* issue beacon to start bss network */ + start_bss_network(padapter, (u8*)pbss_network); + + /* alloc sta_info for ap itself */ + psta = rtw_get_stainfo23a(&padapter->stapriv, pbss_network->MacAddress); + if (!psta) { + psta = rtw_alloc_stainfo23a(&padapter->stapriv, pbss_network->MacAddress); + if (!psta) + return _FAIL; + } + /* fix bug of flush_cam_entry at STOP AP mode */ + psta->state |= WIFI_AP_STATE; + rtw_indicate_connect23a(padapter); + + /* for check if already set beacon */ + pmlmepriv->cur_network.join_res = true; + + return ret; +} + +void rtw_set_macaddr_acl23a(struct rtw_adapter *padapter, int mode) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + + DBG_8723A("%s, mode =%d\n", __func__, mode); + + pacl_list->mode = mode; +} + +int rtw_acl_add_sta23a(struct rtw_adapter *padapter, u8 *addr) +{ + struct list_head *plist, *phead; + u8 added = false; + int i, ret = 0; + struct rtw_wlan_acl_node *paclnode; + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q; + + DBG_8723A("%s(acl_num =%d) =" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); + + if ((NUM_ACL-1) < pacl_list->num) + return -1; + + spin_lock_bh(&pacl_node_q->lock); + + phead = get_list_head(pacl_node_q); + + list_for_each(plist, phead) { + paclnode = container_of(plist, struct rtw_wlan_acl_node, list); + + if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { + if (paclnode->valid == true) { + added = true; + DBG_8723A("%s, sta has been added\n", __func__); + break; + } + } + } + + spin_unlock_bh(&pacl_node_q->lock); + + if (added) + return ret; + + spin_lock_bh(&pacl_node_q->lock); + + for (i = 0; i < NUM_ACL; i++) { + paclnode = &pacl_list->aclnode[i]; + + if (!paclnode->valid) { + INIT_LIST_HEAD(&paclnode->list); + + memcpy(paclnode->addr, addr, ETH_ALEN); + + paclnode->valid = true; + + list_add_tail(&paclnode->list, get_list_head(pacl_node_q)); + + pacl_list->num++; + + break; + } + } + + DBG_8723A("%s, acl_num =%d\n", __func__, pacl_list->num); + + spin_unlock_bh(&pacl_node_q->lock); + return ret; +} + +int rtw_acl_remove_sta23a(struct rtw_adapter *padapter, u8 *addr) +{ + struct list_head *plist, *phead, *ptmp; + struct rtw_wlan_acl_node *paclnode; + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q; + int ret = 0; + + DBG_8723A("%s(acl_num =%d) = %pM\n", __func__, pacl_list->num, addr); + + spin_lock_bh(&pacl_node_q->lock); + + phead = get_list_head(pacl_node_q); + + list_for_each_safe(plist, ptmp, phead) { + paclnode = container_of(plist, struct rtw_wlan_acl_node, list); + + if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { + if (paclnode->valid) { + paclnode->valid = false; + + list_del_init(&paclnode->list); + + pacl_list->num--; + } + } + } + + spin_unlock_bh(&pacl_node_q->lock); + + DBG_8723A("%s, acl_num =%d\n", __func__, pacl_list->num); + + return ret; +} + +static void update_bcn_fixed_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_erpinfo_ie(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + unsigned char *p, *ie = pnetwork->IEs; + u32 len = 0; + + DBG_8723A("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable); + + if (!pmlmeinfo->ERP_enable) + return; + + /* parsing ERP_IE */ + p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (p && len>0) + { + struct ndis_802_11_var_ies * pIE = (struct ndis_802_11_var_ies *)p; + + if (pmlmepriv->num_sta_non_erp == 1) + pIE->data[0] |= WLAN_ERP_NON_ERP_PRESENT | + WLAN_ERP_USE_PROTECTION; + else + pIE->data[0] &= ~(WLAN_ERP_NON_ERP_PRESENT | + WLAN_ERP_USE_PROTECTION); + + if (pmlmepriv->num_sta_no_short_preamble > 0) + pIE->data[0] |= WLAN_ERP_BARKER_PREAMBLE; + else + pIE->data[0] &= ~(WLAN_ERP_BARKER_PREAMBLE); + + ERP_IE_handler23a(padapter, pIE); + } +} + +static void update_bcn_htcap_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_htinfo_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_rsn_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_wpa_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_wmm_ie(struct rtw_adapter *padapter) +{ + DBG_8723A("%s\n", __func__); +} + +static void update_bcn_wps_ie(struct rtw_adapter *padapter) +{ + u8 *pwps_ie = NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie = NULL; + uint wps_ielen = 0, wps_offset, remainder_ielen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + unsigned char *ie = pnetwork->IEs; + u32 ielen = pnetwork->IELength; + + DBG_8723A("%s\n", __func__); + + pwps_ie = rtw_get_wps_ie23a(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen); + + if (pwps_ie == NULL || wps_ielen == 0) + return; + + wps_offset = (uint)(pwps_ie-ie); + + premainder_ie = pwps_ie + wps_ielen; + + remainder_ielen = ielen - wps_offset - wps_ielen; + + if (remainder_ielen > 0) { + pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC); + if (pbackup_remainder_ie) + memcpy(pbackup_remainder_ie, premainder_ie, + remainder_ielen); + } + + pwps_ie_src = pmlmepriv->wps_beacon_ie; + if (pwps_ie_src == NULL) + return; + + wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */ + if ((wps_offset+wps_ielen+2+remainder_ielen)<= MAX_IE_SZ) + { + memcpy(pwps_ie, pwps_ie_src, wps_ielen+2); + pwps_ie += (wps_ielen+2); + + if (pbackup_remainder_ie) + memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); + + /* update IELength */ + pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen; + } + + if (pbackup_remainder_ie) + kfree(pbackup_remainder_ie); +} + +static void update_bcn_p2p_ie(struct rtw_adapter *padapter) +{ +} + +static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8*oui) +{ + DBG_8723A("%s\n", __func__); + + if (!memcmp(RTW_WPA_OUI23A, oui, 4)) + { + update_bcn_wpa_ie(padapter); + } + else if (!memcmp(WMM_OUI23A, oui, 4)) + { + update_bcn_wmm_ie(padapter); + } + else if (!memcmp(WPS_OUI23A, oui, 4)) + { + update_bcn_wps_ie(padapter); + } + else if (!memcmp(P2P_OUI23A, oui, 4)) + { + update_bcn_p2p_ie(padapter); + } + else + { + DBG_8723A("unknown OUI type!\n"); + } +} + +void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx) +{ + struct mlme_priv *pmlmepriv; + struct mlme_ext_priv *pmlmeext; + /* struct mlme_ext_info *pmlmeinfo; */ + + /* DBG_8723A("%s\n", __func__); */ + + if (!padapter) + return; + + pmlmepriv = &padapter->mlmepriv; + pmlmeext = &padapter->mlmeextpriv; + /* pmlmeinfo = &pmlmeext->mlmext_info; */ + + if (false == pmlmeext->bstart_bss) + return; + + spin_lock_bh(&pmlmepriv->bcn_update_lock); + + switch (ie_id) + { + case 0xFF: + + update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ + + break; + + case _TIM_IE_: + + update_BCNTIM(padapter); + + break; + + case _ERPINFO_IE_: + + update_bcn_erpinfo_ie(padapter); + + break; + + case _HT_CAPABILITY_IE_: + + update_bcn_htcap_ie(padapter); + + break; + + case _RSN_IE_2_: + + update_bcn_rsn_ie(padapter); + + break; + + case _HT_ADD_INFO_IE_: + + update_bcn_htinfo_ie(padapter); + + break; + + case _VENDOR_SPECIFIC_IE_: + + update_bcn_vendor_spec_ie(padapter, oui); + + break; + + default: + break; + } + + pmlmepriv->update_bcn = true; + + spin_unlock_bh(&pmlmepriv->bcn_update_lock); + + if (tx) + set_tx_beacon_cmd23a(padapter); +} + +/* +op_mode +Set to 0 (HT pure) under the followign conditions + - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or + - all STAs in the BSS are 20 MHz HT in 20 MHz BSS +Set to 1 (HT non-member protection) if there may be non-HT STAs + in both the primary and the secondary channel +Set to 2 if only HT STAs are associated in BSS, + however and at least one 20 MHz HT STA is associated +Set to 3 (HT mixed mode) when one or more non-HT STAs are associated + (currently non-GF HT station is considered as non-HT STA also) +*/ +static int rtw_ht_operation_update(struct rtw_adapter *padapter) +{ + u16 cur_op_mode, new_op_mode; + int op_mode_changes = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; + + if (pmlmepriv->htpriv.ht_option == true) + return 0; + + /* if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) */ + /* return 0; */ + + DBG_8723A("%s current operation mode = 0x%X\n", + __func__, pmlmepriv->ht_op_mode); + + if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) + && pmlmepriv->num_sta_ht_no_gf) { + pmlmepriv->ht_op_mode |= + HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; + op_mode_changes++; + } else if ((pmlmepriv->ht_op_mode & + HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && + pmlmepriv->num_sta_ht_no_gf == 0) { + pmlmepriv->ht_op_mode &= + ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; + op_mode_changes++; + } + + if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && + (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) { + pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; + op_mode_changes++; + } else if ((pmlmepriv->ht_op_mode & + HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && + (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) { + pmlmepriv->ht_op_mode &= + ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; + op_mode_changes++; + } + + /* Note: currently we switch to the MIXED op mode if HT non-greenfield + * station is associated. Probably it's a theoretical case, since + * it looks like all known HT STAs support greenfield. + */ + new_op_mode = 0; + if (pmlmepriv->num_sta_no_ht || + (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) + new_op_mode = OP_MODE_MIXED; + else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + && pmlmepriv->num_sta_ht_20mhz) + new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; + else if (pmlmepriv->olbc_ht) + new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; + else + new_op_mode = OP_MODE_PURE; + + cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; + if (cur_op_mode != new_op_mode) { + pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; + pmlmepriv->ht_op_mode |= new_op_mode; + op_mode_changes++; + } + + DBG_8723A("%s new operation mode = 0x%X changes =%d\n", + __func__, pmlmepriv->ht_op_mode, op_mode_changes); + + return op_mode_changes; +} + +void associated_clients_update23a(struct rtw_adapter *padapter, u8 updated) +{ + /* update associcated stations cap. */ + if (updated == true) + { + struct list_head *phead, *plist, *ptmp; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + VCS_update23a(padapter, psta); + } + + spin_unlock_bh(&pstapriv->asoc_list_lock); + } +} + +/* called > TSR LEVEL for USB or SDIO Interface*/ +void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + u8 beacon_updated = false; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) + { + if (!psta->no_short_preamble_set) + { + psta->no_short_preamble_set = 1; + + pmlmepriv->num_sta_no_short_preamble++; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_preamble == 1)) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + + } + } + else + { + if (psta->no_short_preamble_set) + { + psta->no_short_preamble_set = 0; + + pmlmepriv->num_sta_no_short_preamble--; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_preamble == 0)) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + + } + } + + if (psta->flags & WLAN_STA_NONERP) + { + if (!psta->nonerp_set) + { + psta->nonerp_set = 1; + + pmlmepriv->num_sta_non_erp++; + + if (pmlmepriv->num_sta_non_erp == 1) + { + beacon_updated = true; + update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + } + } + + } + else + { + if (psta->nonerp_set) + { + psta->nonerp_set = 0; + + pmlmepriv->num_sta_non_erp--; + + if (pmlmepriv->num_sta_non_erp == 0) + { + beacon_updated = true; + update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + } + } + + } + + if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)) + { + if (!psta->no_short_slot_time_set) + { + psta->no_short_slot_time_set = 1; + + pmlmepriv->num_sta_no_short_slot_time++; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_slot_time == 1)) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + + } + } + else + { + if (psta->no_short_slot_time_set) + { + psta->no_short_slot_time_set = 0; + + pmlmepriv->num_sta_no_short_slot_time--; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_slot_time == 0)) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + } + } + + if (psta->flags & WLAN_STA_HT) + { + u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); + + DBG_8723A("HT: STA " MAC_FMT " HT Capabilities " + "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); + + if (psta->no_ht_set) { + psta->no_ht_set = 0; + pmlmepriv->num_sta_no_ht--; + } + + if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { + if (!psta->no_ht_gf_set) { + psta->no_ht_gf_set = 1; + pmlmepriv->num_sta_ht_no_gf++; + } + DBG_8723A("%s STA " MAC_FMT " - no " + "greenfield, num of non-gf stations %d\n", + __func__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_ht_no_gf); + } + + if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH_20_40) == 0) { + if (!psta->ht_20mhz_set) { + psta->ht_20mhz_set = 1; + pmlmepriv->num_sta_ht_20mhz++; + } + DBG_8723A("%s STA " MAC_FMT " - 20 MHz HT, " + "num of 20MHz HT STAs %d\n", + __func__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_ht_20mhz); + } + + } + else + { + if (!psta->no_ht_set) { + psta->no_ht_set = 1; + pmlmepriv->num_sta_no_ht++; + } + if (pmlmepriv->htpriv.ht_option == true) { + DBG_8723A("%s STA " MAC_FMT + " - no HT, num of non-HT stations %d\n", + __func__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_no_ht); + } + } + + if (rtw_ht_operation_update(padapter) > 0) + { + update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false); + update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true); + } + + /* update associcated stations cap. */ + associated_clients_update23a(padapter, beacon_updated); + + DBG_8723A("%s, updated =%d\n", __func__, beacon_updated); +} + +u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + u8 beacon_updated = false; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!psta) + return beacon_updated; + + if (psta->no_short_preamble_set) { + psta->no_short_preamble_set = 0; + pmlmepriv->num_sta_no_short_preamble--; + if (pmlmeext->cur_wireless_mode > WIRELESS_11B + && pmlmepriv->num_sta_no_short_preamble == 0) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + } + + if (psta->nonerp_set) { + psta->nonerp_set = 0; + pmlmepriv->num_sta_non_erp--; + if (pmlmepriv->num_sta_non_erp == 0) + { + beacon_updated = true; + update_beacon23a(padapter, _ERPINFO_IE_, NULL, true); + } + } + + if (psta->no_short_slot_time_set) { + psta->no_short_slot_time_set = 0; + pmlmepriv->num_sta_no_short_slot_time--; + if (pmlmeext->cur_wireless_mode > WIRELESS_11B + && pmlmepriv->num_sta_no_short_slot_time == 0) + { + beacon_updated = true; + update_beacon23a(padapter, 0xFF, NULL, true); + } + } + + if (psta->no_ht_gf_set) { + psta->no_ht_gf_set = 0; + pmlmepriv->num_sta_ht_no_gf--; + } + + if (psta->no_ht_set) { + psta->no_ht_set = 0; + pmlmepriv->num_sta_no_ht--; + } + + if (psta->ht_20mhz_set) { + psta->ht_20mhz_set = 0; + pmlmepriv->num_sta_ht_20mhz--; + } + + if (rtw_ht_operation_update(padapter) > 0) + { + update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false); + update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true); + } + + /* update associcated stations cap. */ + + DBG_8723A("%s, updated =%d\n", __func__, beacon_updated); + + return beacon_updated; +} + +u8 ap_free_sta23a(struct rtw_adapter *padapter, struct sta_info *psta, bool active, u16 reason) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + u8 beacon_updated = false; + + if (!psta) + return beacon_updated; + + if (active == true) + { + /* tear down Rx AMPDU */ + send_delba23a(padapter, 0, psta->hwaddr);/* recipient */ + + /* tear down TX AMPDU */ + send_delba23a(padapter, 1, psta->hwaddr);/* originator */ + + issue_deauth23a(padapter, psta->hwaddr, reason); + } + + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ + + /* report_del_sta_event23a(padapter, psta->hwaddr, reason); */ + + /* clear cam entry / key */ + /* clear_cam_entry23a(padapter, (psta->mac_id + 3)); */ + rtw_clearstakey_cmd23a(padapter, (u8*)psta, (u8)(psta->mac_id + 3), true); + + spin_lock_bh(&psta->lock); + psta->state &= ~_FW_LINKED; + spin_unlock_bh(&psta->lock); + + rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); + + report_del_sta_event23a(padapter, psta->hwaddr, reason); + + beacon_updated = bss_cap_update_on_sta_leave23a(padapter, psta); + + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(padapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + + return beacon_updated; +} + +int rtw_ap_inform_ch_switch23a (struct rtw_adapter *padapter, u8 new_ch, u8 ch_offset) +{ + struct list_head *phead, *plist; + int ret = 0; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return ret; + + DBG_8723A(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); + + spin_lock_bh(&pstapriv->asoc_list_lock); + phead = &pstapriv->asoc_list; + + list_for_each(plist, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + issue_action_spct_ch_switch23a (padapter, psta->hwaddr, new_ch, ch_offset); + psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + issue_action_spct_ch_switch23a (padapter, bc_addr, new_ch, ch_offset); + + return ret; +} + +int rtw_sta_flush23a(struct rtw_adapter *padapter) +{ + struct list_head *phead, *plist, *ptmp; + int ret = 0; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 chk_alive_num = 0; + char chk_alive_list[NUM_STA]; + int i; + + DBG_8723A(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return ret; + + spin_lock_bh(&pstapriv->asoc_list_lock); + phead = &pstapriv->asoc_list; + + list_for_each_safe(plist, ptmp, phead) { + int stainfo_offset; + + psta = container_of(plist, struct sta_info, asoc_list); + + /* Remove sta from asoc_list */ + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + + /* Keep sta for ap_free_sta23a() beyond this asoc_list loop */ + stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) { + chk_alive_list[chk_alive_num++] = stainfo_offset; + } + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + /* For each sta in chk_alive_list, call ap_free_sta23a */ + for (i = 0; i < chk_alive_num; i++) { + psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]); + ap_free_sta23a(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); + } + + issue_deauth23a(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); + + associated_clients_update23a(padapter, true); + + return ret; +} + +/* called > TSR LEVEL for USB or SDIO Interface*/ +void sta_info_update23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + int flags = psta->flags; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + /* update wmm cap. */ + if (WLAN_STA_WME&flags) + psta->qos_option = 1; + else + psta->qos_option = 0; + + if (pmlmepriv->qospriv.qos_option == 0) + psta->qos_option = 0; + + /* update 802.11n ht cap. */ + if (WLAN_STA_HT&flags) + { + psta->htpriv.ht_option = true; + psta->qos_option = 1; + } + else + { + psta->htpriv.ht_option = false; + } + + if (pmlmepriv->htpriv.ht_option == false) + psta->htpriv.ht_option = false; + + update_sta_info23a_apmode23a(padapter, psta); +} + +/* called >= TSR LEVEL for USB or SDIO Interface*/ +void ap_sta_info_defer_update23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + if (psta->state & _FW_LINKED) + { + /* add ratid */ + add_RATid23a(padapter, psta, 0);/* DM_RATR_STA_INIT */ + } +} + +/* restore hw setting from sw data structures */ +void rtw_ap_restore_network(struct rtw_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct sta_priv * pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct list_head *phead, *plist, *ptmp; + u8 chk_alive_num = 0; + char chk_alive_list[NUM_STA]; + int i; + + rtw_setopmode_cmd23a(padapter, Ndis802_11APMode); + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + start_bss_network(padapter, (u8*)&mlmepriv->cur_network.network); + + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) + { + /* restore group key, WEP keys is restored in ips_leave23a() */ + rtw_set_key23a(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0); + } + + /* per sta pairwise key and settings */ + if ((padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_) && + (padapter->securitypriv.dot11PrivacyAlgrthm != _AES_)) { + return; + } + + spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + + list_for_each_safe(plist, ptmp, phead) { + int stainfo_offset; + + psta = container_of(plist, struct sta_info, asoc_list); + + stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) { + chk_alive_list[chk_alive_num++] = stainfo_offset; + } + } + + spin_unlock_bh(&pstapriv->asoc_list_lock); + + for (i = 0; i < chk_alive_num; i++) { + psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]); + + if (psta == NULL) { + DBG_8723A(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter)); + } + else if (psta->state &_FW_LINKED) + { + Update_RA_Entry23a(padapter, psta); + /* pairwise key */ + rtw_setstakey_cmd23a(padapter, (unsigned char *)psta, true); + } + } +} + +void start_ap_mode23a(struct rtw_adapter *padapter) +{ + int i; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + + pmlmepriv->update_bcn = false; + + /* init_mlme_ap_info23a(padapter); */ + pmlmeext->bstart_bss = false; + + pmlmepriv->num_sta_non_erp = 0; + + pmlmepriv->num_sta_no_short_slot_time = 0; + + pmlmepriv->num_sta_no_short_preamble = 0; + + pmlmepriv->num_sta_ht_no_gf = 0; + pmlmepriv->num_sta_no_ht = 0; + pmlmepriv->num_sta_ht_20mhz = 0; + + pmlmepriv->olbc = false; + + pmlmepriv->olbc_ht = false; + + pmlmepriv->ht_op_mode = 0; + + for (i = 0; ista_aid[i] = NULL; + + pmlmepriv->wps_beacon_ie = NULL; + pmlmepriv->wps_probe_resp_ie = NULL; + pmlmepriv->wps_assoc_resp_ie = NULL; + + pmlmepriv->p2p_beacon_ie = NULL; + pmlmepriv->p2p_probe_resp_ie = NULL; + + /* for ACL */ + INIT_LIST_HEAD(&pacl_list->acl_node_q.queue); + pacl_list->num = 0; + pacl_list->mode = 0; + for (i = 0; i < NUM_ACL; i++) { + INIT_LIST_HEAD(&pacl_list->aclnode[i].list); + pacl_list->aclnode[i].valid = false; + } +} + +void stop_ap_mode23a(struct rtw_adapter *padapter) +{ + struct list_head *phead, *plist, *ptmp; + struct rtw_wlan_acl_node *paclnode; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q; + + pmlmepriv->update_bcn = false; + pmlmeext->bstart_bss = false; + + /* reset and init security priv , this can refine with rtw_reset_securitypriv23a */ + memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); + padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; + padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; + + /* for ACL */ + spin_lock_bh(&pacl_node_q->lock); + phead = get_list_head(pacl_node_q); + + list_for_each_safe(plist, ptmp, phead) { + paclnode = container_of(plist, struct rtw_wlan_acl_node, list); + + if (paclnode->valid == true) { + paclnode->valid = false; + + list_del_init(&paclnode->list); + + pacl_list->num--; + } + } + spin_unlock_bh(&pacl_node_q->lock); + + DBG_8723A("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num); + + rtw_sta_flush23a(padapter); + + /* free_assoc_sta_resources */ + rtw_free_all_stainfo23a(padapter); + + psta = rtw_get_bcmc_stainfo23a(padapter); + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(padapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + + rtw_init_bcmc_stainfo23a(padapter); + + rtw23a_free_mlme_priv_ie_data(pmlmepriv); +} + +#endif /* CONFIG_8723AU_AP_MODE */ diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c new file mode 100644 index 000000000000..dbc6401c6e13 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_cmd.c @@ -0,0 +1,1874 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_CMD_C_ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_8723AU_BT_COEXIST +#include +#endif /* CONFIG_8723AU_BT_COEXIST */ + +static struct cmd_hdl wlancmds[] = { + GEN_DRV_CMD_HANDLER(0, NULL) /*0*/ + GEN_DRV_CMD_HANDLER(0, NULL) + GEN_DRV_CMD_HANDLER(0, NULL) + GEN_DRV_CMD_HANDLER(0, NULL) + GEN_DRV_CMD_HANDLER(0, NULL) + GEN_DRV_CMD_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) /*10*/ + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct wlan_bssid_ex), join_cmd_hdl23a) /*14*/ + GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof (struct wlan_bssid_ex), createbss_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm), sitesurvey_cmd_hdl23a) /*18*/ + GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl23a) /*20*/ + GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL) /*30*/ + GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL) + GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) /*40*/ + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl23a) + GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl23a) /* 46 */ + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) /*50*/ + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(0, NULL) + GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl23a) /*55*/ + + GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl23a) /*56*/ + GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl23a) /*57*/ + + GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl23a) /*58*/ + GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl23a) /*59*/ + GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl23a) /*60*/ + + GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl23a) /*61*/ + GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl23a) /*62*/ +}; + +struct _cmd_callback rtw_cmd_callback[] = { + {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ + {GEN_CMD_CODE(_Write_MACREG), NULL}, + {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback23a}, + {GEN_CMD_CODE(_Write_BBREG), NULL}, + {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback23a}, + {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ + {GEN_CMD_CODE(_Read_EEPROM), NULL}, + {GEN_CMD_CODE(_Write_EEPROM), NULL}, + {GEN_CMD_CODE(_Read_EFUSE), NULL}, + {GEN_CMD_CODE(_Write_EFUSE), NULL}, + + {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ + {GEN_CMD_CODE(_Write_CAM), NULL}, + {GEN_CMD_CODE(_setBCNITV), NULL}, + {GEN_CMD_CODE(_setMBIDCFG), NULL}, + {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd23a_callback}, /*14*/ + {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd23a_callback}, /*15*/ + {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd23a_callback}, + {GEN_CMD_CODE(_SetOpMode), NULL}, + {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback23a}, /*18*/ + {GEN_CMD_CODE(_SetAuth), NULL}, + + {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ + {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback23a}, + {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback23a}, + {GEN_CMD_CODE(_DelAssocSta), NULL}, + {GEN_CMD_CODE(_SetStaPwrState), NULL}, + {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ + {GEN_CMD_CODE(_GetBasicRate), NULL}, + {GEN_CMD_CODE(_SetDataRate), NULL}, + {GEN_CMD_CODE(_GetDataRate), NULL}, + {GEN_CMD_CODE(_SetPhyInfo), NULL}, + + {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ + {GEN_CMD_CODE(_SetPhy), NULL}, + {GEN_CMD_CODE(_GetPhy), NULL}, + {GEN_CMD_CODE(_readRssi), NULL}, + {GEN_CMD_CODE(_readGain), NULL}, + {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ + {GEN_CMD_CODE(_SetPwrMode), NULL}, + {GEN_CMD_CODE(_JoinbssRpt), NULL}, + {GEN_CMD_CODE(_SetRaTable), NULL}, + {GEN_CMD_CODE(_GetRaTable), NULL}, + + {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ + {GEN_CMD_CODE(_GetDTMReport), NULL}, + {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, + {GEN_CMD_CODE(_SetUsbSuspend), NULL}, + {GEN_CMD_CODE(_SetH2cLbk), NULL}, + {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ + {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ + {GEN_CMD_CODE(_SetTxPower), NULL}, + {GEN_CMD_CODE(_SwitchAntenna), NULL}, + {GEN_CMD_CODE(_SetCrystalCap), NULL}, + {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ + + {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/ + {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, + {GEN_CMD_CODE(_SetContinuousTx), NULL}, + {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ + {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/ + + {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/ + {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ + {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ + {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ + {GEN_CMD_CODE(_LedBlink), NULL},/*60*/ + + {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/ + {GEN_CMD_CODE(_TDLS), NULL},/*62*/ +}; + +/* +Caller and the rtw_cmd_thread23a can protect cmd_q by spin_lock. +No irqsave is necessary. +*/ + +int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv) +{ + int res = _SUCCESS; + + sema_init(&pcmdpriv->cmd_queue_sema, 0); + sema_init(&pcmdpriv->terminate_cmdthread_sema, 0); + + _rtw_init_queue23a(&pcmdpriv->cmd_queue); + + pcmdpriv->cmd_seq = 1; + + pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, + GFP_KERNEL); + + if (pcmdpriv->cmd_allocated_buf == NULL) { + res = _FAIL; + goto exit; + } + + pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - + ((unsigned long)(pcmdpriv->cmd_allocated_buf) & + (CMDBUFF_ALIGN_SZ - 1)); + + pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL); + + if (!pcmdpriv->rsp_allocated_buf) { + res = _FAIL; + goto exit; + } + + pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - + ((unsigned long)(pcmdpriv->rsp_allocated_buf) & 3); + + pcmdpriv->cmd_issued_cnt = 0; + pcmdpriv->cmd_done_cnt = 0; + pcmdpriv->rsp_cnt = 0; + +exit: + + return res; +} + +/* forward definition */ + +static void c2h_wk_callback(struct work_struct *work); +int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv) +{ + int res = _SUCCESS; + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + atomic_set(&pevtpriv->event_seq, 0); + pevtpriv->evt_done_cnt = 0; + + INIT_WORK(&pevtpriv->c2h_wk, c2h_wk_callback); + pevtpriv->c2h_wk_alive = false; + pevtpriv->c2h_queue = rtw_cbuf_alloc23a(C2H_QUEUE_MAX_LEN + 1); + + return res; +} + +void _rtw_free_evt_priv23a (struct evt_priv *pevtpriv) +{ + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("+_rtw_free_evt_priv23a\n")); + cancel_work_sync(&pevtpriv->c2h_wk); + while(pevtpriv->c2h_wk_alive) + msleep(10); + + while (!rtw_cbuf_empty23a(pevtpriv->c2h_queue)) { + void *c2h; + if ((c2h = rtw_cbuf_pop23a(pevtpriv->c2h_queue)) != NULL && + c2h != (void *)pevtpriv) { + kfree(c2h); + } + } + + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("-_rtw_free_evt_priv23a\n")); +} + +void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv) +{ + if (pcmdpriv) { + kfree(pcmdpriv->cmd_allocated_buf); + kfree(pcmdpriv->rsp_allocated_buf); + } +} + +/* +Calling Context: +rtw_enqueue_cmd23a can only be called between kernel thread, +since only spin_lock is used. + +ISR/Call-Back functions can't call this sub-function. +*/ + +int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj) +{ + unsigned long irqL; + + if (obj == NULL) + goto exit; + + spin_lock_irqsave(&queue->lock, irqL); + + list_add_tail(&obj->list, &queue->queue); + + spin_unlock_irqrestore(&queue->lock, irqL); + +exit: + + return _SUCCESS; +} + +u32 rtw_init_evt_priv23a(struct evt_priv *pevtpriv) +{ + int res; + + res = _rtw_init_evt_priv23a(pevtpriv); + + return res; +} + +void rtw_free_evt_priv23a(struct evt_priv *pevtpriv) +{ + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("rtw_free_evt_priv23a\n")); + _rtw_free_evt_priv23a(pevtpriv); +} + +void rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv) +{ + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("rtw_free_cmd_priv23a\n")); + _rtw_free_cmd_priv23a(pcmdpriv); +} + +static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +{ + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + /* set to true to allow enqueuing cmd when hw_init_completed is false */ + u8 bAllow = false; + + /* To decide allow or not */ + if (pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect && + !pcmdpriv->padapter->registrypriv.usbss_enable) { + if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + pdrvextra_cmd_parm = + (struct drvextra_cmd_parm *)cmd_obj->parmbuf; + if (pdrvextra_cmd_parm->ec_id == + POWER_SAVING_CTRL_WK_CID) + bAllow = true; + } + } + + if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) + bAllow = true; + + if ((pcmdpriv->padapter->hw_init_completed == false && + bAllow == false) || pcmdpriv->cmdthd_running == false) + return _FAIL; + return _SUCCESS; +} + +u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +{ + int res = _FAIL; + struct rtw_adapter *padapter = pcmdpriv->padapter; + + if (!cmd_obj) + goto exit; + + cmd_obj->padapter = padapter; + + res = rtw_cmd_filter(pcmdpriv, cmd_obj); + if (res == _FAIL) { + rtw_free_cmd_obj23a(cmd_obj); + goto exit; + } + + res = _rtw_enqueue_cmd23a(&pcmdpriv->cmd_queue, cmd_obj); + + if (res == _SUCCESS) + up(&pcmdpriv->cmd_queue_sema); + +exit: + return res; +} + +static struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) +{ + struct cmd_obj *obj; + struct rtw_queue *queue = &pcmdpriv->cmd_queue; + unsigned long irqL; + + spin_lock_irqsave(&queue->lock, irqL); + if (list_empty(&queue->queue)) + obj = NULL; + else { + obj = container_of((&queue->queue)->next, struct cmd_obj, list); + list_del_init(&obj->list); + } + + spin_unlock_irqrestore(&queue->lock, irqL); + + return obj; +} + +void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv) +{ + pcmdpriv->cmd_done_cnt++; +} + +void rtw_free_cmd_obj23a(struct cmd_obj *pcmd) +{ + + if (pcmd->cmdcode != _JoinBss_CMD_ && + pcmd->cmdcode != _CreateBss_CMD_) { + /* free parmbuf in cmd_obj */ + kfree(pcmd->parmbuf); + } + + if (pcmd->rsp) { + if (pcmd->rspsz != 0) { + /* free rsp in cmd_obj */ + kfree(pcmd->rsp); + } + } + + kfree(pcmd); +} + +int rtw_cmd_thread23a(void *context) +{ + u8 ret; + struct cmd_obj *pcmd; + u8 *pcmdbuf, *prspbuf; + u8 (*cmd_hdl)(struct rtw_adapter *padapter, u8* pbuf); + void (*pcmd_callback)(struct rtw_adapter *dev, struct cmd_obj *pcmd); + struct rtw_adapter *padapter = (struct rtw_adapter *)context; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + allow_signal(SIGTERM); + + pcmdbuf = pcmdpriv->cmd_buf; + prspbuf = pcmdpriv->rsp_buf; + + pcmdpriv->cmdthd_running = true; + up(&pcmdpriv->terminate_cmdthread_sema); + + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("start r871x rtw_cmd_thread23a !!!!\n")); + + while(1) { + if (down_interruptible(&pcmdpriv->cmd_queue_sema)) + break; +_next: + if ((padapter->bDriverStopped == true) || + (padapter->bSurpriseRemoved == true)) { + DBG_8723A("%s: DriverStopped(%d) SurpriseRemoved(%d) " + "break at line %d\n", __func__, + padapter->bDriverStopped, + padapter->bSurpriseRemoved, __LINE__); + break; + } + + if (!(pcmd = rtw_dequeue_cmd(pcmdpriv))) + continue; + + if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) { + pcmd->res = H2C_DROPPED; + goto post_process; + } + + pcmdpriv->cmd_issued_cnt++; + + pcmd->cmdsz = _RND4(pcmd->cmdsz);/* _RND4 */ + + memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); + + if (pcmd->cmdcode < (sizeof(wlancmds)/sizeof(struct cmd_hdl))) { + cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; + + if (cmd_hdl) { + ret = cmd_hdl(pcmd->padapter, pcmdbuf); + pcmd->res = ret; + } + + pcmdpriv->cmd_seq++; + } else + pcmd->res = H2C_PARAMETERS_ERROR; + + cmd_hdl = NULL; + +post_process: + /* call callback function for post-processed */ + if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) / + sizeof(struct _cmd_callback))) { + pcmd_callback = + rtw_cmd_callback[pcmd->cmdcode].callback; + if (!pcmd_callback) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("mlme_cmd_hdl(): pcmd_callback = " + "0x%p, cmdcode = 0x%x\n", + pcmd_callback, pcmd->cmdcode)); + rtw_free_cmd_obj23a(pcmd); + } else { + /* todo: !!! fill rsp_buf to pcmd->rsp + if (pcmd->rsp!= NULL) */ + /* need conider that free cmd_obj in + rtw_cmd_callback */ + pcmd_callback(pcmd->padapter, pcmd); + } + } else { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("%s: cmdcode = 0x%x callback not defined!\n", + __func__, pcmd->cmdcode)); + rtw_free_cmd_obj23a(pcmd); + } + + if (signal_pending (current)) + flush_signals(current); + + goto _next; + + } + pcmdpriv->cmdthd_running = false; + + /* free all cmd_obj resources */ + do { + pcmd = rtw_dequeue_cmd(pcmdpriv); + if (!pcmd) + break; + + rtw_free_cmd_obj23a(pcmd); + } while(1); + + up(&pcmdpriv->terminate_cmdthread_sema); + + complete_and_exit(NULL, 0); +} + +u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter, + struct cfg80211_ssid *ssid, int ssid_num, + struct rtw_ieee80211_channel *ch, int ch_num) +{ + u8 res = _FAIL; + struct cmd_obj *ph2c; + struct sitesurvey_parm *psurveyPara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SCAN, 1); + +#ifdef CONFIG_8723AU_P2P + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + p2p_ps_wk_cmd23a(padapter, P2P_PS_SCAN, 1); + } +#endif /* CONFIG_8723AU_P2P */ + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) + return _FAIL; + + psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); + if (!psurveyPara) { + kfree(ph2c); + return _FAIL; + } + + rtw_free_network_queue23a(padapter, false); + + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("%s: flush network queue\n", __func__)); + + init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, + GEN_CMD_CODE(_SiteSurvey)); + + /* psurveyPara->bsslimit = 48; */ + psurveyPara->scan_mode = pmlmepriv->scan_mode; + + /* prepare ssid list */ + if (ssid) { + int i; + for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { + if (ssid[i].ssid_len) { + memcpy(&psurveyPara->ssid[i], &ssid[i], + sizeof(struct cfg80211_ssid)); + psurveyPara->ssid_num++; + if (0) + DBG_8723A(FUNC_ADPT_FMT" ssid:(%s, %d)\n", + FUNC_ADPT_ARG(padapter), + psurveyPara->ssid[i].ssid, + psurveyPara->ssid[i].ssid_len); + } + } + } + + /* prepare channel list */ + if (ch) { + int i; + for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { + if (ch[i].hw_value && + !(ch[i].flags & IEEE80211_CHAN_DISABLED)) { + memcpy(&psurveyPara->ch[i], &ch[i], + sizeof(struct rtw_ieee80211_channel)); + psurveyPara->ch_num++; + if (0) + DBG_8723A(FUNC_ADPT_FMT" ch:%u\n", + FUNC_ADPT_ARG(padapter), + psurveyPara->ch[i].hw_value); + } + } + } + + set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + + if (res == _SUCCESS) { + mod_timer(&pmlmepriv->scan_to_timer, jiffies + + msecs_to_jiffies(SCANNING_TIMEOUT)); + + rtw_led_control(padapter, LED_CTL_SITE_SURVEY); + + pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ + } else + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + return res; +} + +void rtw_getbbrfreg_cmdrsp_callback23a(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + kfree(pcmd->parmbuf); + kfree(pcmd); +} + +u8 rtw_createbss_cmd23a(struct rtw_adapter *padapter) +{ + struct cmd_obj *pcmd; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *pdev_network; + u8 res = _SUCCESS; + + pdev_network = &padapter->registrypriv.dev_network; + + rtw_led_control(padapter, LED_CTL_START_TO_LINK); + + if (pmlmepriv->assoc_ssid.ssid_len == 0) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + (" createbss for Any SSid:%s\n", + pmlmepriv->assoc_ssid.ssid)); + } else { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + (" createbss for SSid:%s\n", + pmlmepriv->assoc_ssid.ssid)); + } + + pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!pcmd) { + res = _FAIL; + goto exit; + } + + INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _CreateBss_CMD_; + pcmd->parmbuf = (unsigned char *)pdev_network; + pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex*)pdev_network); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + pdev_network->Length = pcmd->cmdsz; + + res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); + +exit: + + return res; +} + +u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, + struct wlan_network * pnetwork) +{ + u8 *auth, res = _SUCCESS; + uint t_len = 0; + struct wlan_bssid_ex *psecnetwork; + struct cmd_obj *pcmd; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + enum ndis_802_11_net_infra ndis_network_mode; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + ndis_network_mode = pnetwork->network.InfrastructureMode; + + rtw_led_control(padapter, LED_CTL_START_TO_LINK); + + if (pmlmepriv->assoc_ssid.ssid_len == 0) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, + ("+Join cmd: Any SSid\n")); + } else { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, + ("+Join cmd: SSid =[%s]\n", + pmlmepriv->assoc_ssid.ssid)); + } + + pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!pcmd) { + res = _FAIL; + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("rtw_joinbss_cmd23a: memory allocate for cmd_obj " + "fail!!!\n")); + goto exit; + } + /* for IEs is fix buf size */ + t_len = sizeof(struct wlan_bssid_ex); + + /* for hidden ap to set fw_state here */ + if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) { + switch (ndis_network_mode) { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + case Ndis802_11APMode: + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + } + } + + psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss; + if (!psecnetwork) { + if (pcmd) + kfree(pcmd); + + res = _FAIL; + + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("rtw_joinbss_cmd23a :psecnetwork == NULL!!!\n")); + + goto exit; + } + + memset(psecnetwork, 0, t_len); + + memcpy(psecnetwork, &pnetwork->network, + get_wlan_bssid_ex_sz(&pnetwork->network)); + + auth = &psecuritypriv->authenticator_ie[0]; + psecuritypriv->authenticator_ie[0] = + (unsigned char)psecnetwork->IELength; + + if ((psecnetwork->IELength-12) < (256-1)) { + memcpy(&psecuritypriv->authenticator_ie[1], + &psecnetwork->IEs[12], psecnetwork->IELength - 12); + } else { + memcpy(&psecuritypriv->authenticator_ie[1], + &psecnetwork->IEs[12], 256 - 1); + } + + psecnetwork->IELength = 0; + /* Added by Albert 2009/02/18 */ + /* If the the driver wants to use the bssid to create the + * connection. If not, we have to copy the connecting AP's + * MAC address to it so that the driver just has the bssid + * information for PMKIDList searching. */ + + if (pmlmepriv->assoc_by_bssid == false) + ether_addr_copy(&pmlmepriv->assoc_bssid[0], + &pnetwork->network.MacAddress[0]); + + psecnetwork->IELength = + rtw_restruct_sec_ie23a(padapter, &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength); + + pqospriv->qos_option = 0; + + if (pregistrypriv->wmm_enable) { + u32 tmp_len; + + tmp_len = rtw_restruct_wmm_ie23a(padapter, + &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength, + psecnetwork->IELength); + + if (psecnetwork->IELength != tmp_len) { + psecnetwork->IELength = tmp_len; + /* There is WMM IE in this corresp. beacon */ + pqospriv->qos_option = 1; + } else { + /* There is no WMM IE in this corresp. beacon */ + pqospriv->qos_option = 0; + } + } + + phtpriv->ht_option = false; + if (pregistrypriv->ht_enable) { + /* Added by Albert 2010/06/23 */ + /* For the WEP mode, we will use the bg mode to do + the connection to avoid some IOT issue. */ + /* Especially for Realtek 8192u SoftAP. */ + if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && + (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && + (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) { + /* rtw_restructure_ht_ie23a */ + rtw_restructure_ht_ie23a(padapter, + &pnetwork->network.IEs[0], + &psecnetwork->IEs[0], + pnetwork->network.IELength, + &psecnetwork->IELength); + } + } + + pmlmeinfo->assoc_AP_vendor = + check_assoc_AP23a(pnetwork->network.IEs, + pnetwork->network.IELength); + + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA) + padapter->pwrctrlpriv.smart_ps = 0; + else + padapter->pwrctrlpriv.smart_ps = + padapter->registrypriv.smart_ps; + + DBG_8723A("%s: smart_ps =%d\n", __func__, + padapter->pwrctrlpriv.smart_ps); + + /* get cmdsz before endian conversion */ + pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork); + + INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ + pcmd->parmbuf = (unsigned char *)psecnetwork; + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); +exit: + + return res; +} + +u8 rtw_disassoc_cmd23a(struct rtw_adapter*padapter, u32 deauth_timeout_ms, + bool enqueue) +{ + struct cmd_obj *cmdobj = NULL; + struct disconnect_parm *param = NULL; + struct cmd_priv *cmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, + ("+rtw_disassoc_cmd23a\n")); + + /* prepare cmd parameter */ + param = kzalloc(sizeof(*param), GFP_ATOMIC); + if (param == NULL) { + res = _FAIL; + goto exit; + } + param->deauth_timeout_ms = deauth_timeout_ms; + + if (enqueue) { + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!cmdobj) { + res = _FAIL; + kfree(param); + goto exit; + } + init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); + res = rtw_enqueue_cmd23a(cmdpriv, cmdobj); + } else { + /* no need to enqueue, do the cmd hdl directly and + free cmd parameter */ + if (H2C_SUCCESS != disconnect_hdl23a(padapter, (u8 *)param)) + res = _FAIL; + kfree(param); + } + +exit: + return res; +} + +u8 rtw_setopmode_cmd23a(struct rtw_adapter *padapter, + enum ndis_802_11_net_infra networktype) +{ + struct cmd_obj *ph2c; + struct setopmode_parm *psetop; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!ph2c) { + res = false; + goto exit; + } + psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL); + + if (!psetop) { + kfree(ph2c); + res = false; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); + psetop->mode = (u8)networktype; + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_setstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 unicast_key) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct set_stakey_rsp *psetstakey_rsp = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sta_info *sta = (struct sta_info*)psta; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL); + if (!psetstakey_para) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL); + if (!psetstakey_rsp) { + kfree(ph2c); + kfree(psetstakey_para); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + ph2c->rsp = (u8 *) psetstakey_rsp; + ph2c->rspsz = sizeof(struct set_stakey_rsp); + + ether_addr_copy(psetstakey_para->addr, sta->hwaddr); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + psetstakey_para->algorithm = + (unsigned char)psecuritypriv->dot11PrivacyAlgrthm; + } else { + GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, + false); + } + + if (unicast_key == true) { + memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); + } else { + int idx = psecuritypriv->dot118021XGrpKeyid; + memcpy(&psetstakey_para->key, + &psecuritypriv->dot118021XGrpKey[idx].skey, 16); + } + + /* jeff: set this becasue at least sw key is ready */ + padapter->securitypriv.busetkipkey = true; + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + +exit: + + return res; +} + +u8 rtw_clearstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 entry, + u8 enqueue) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct set_stakey_rsp *psetstakey_rsp = NULL; + struct sta_info *sta = (struct sta_info *)psta; + u8 res = _SUCCESS; + + if (!enqueue) { + clear_cam_entry23a(padapter, entry); + } else { + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), + GFP_KERNEL); + if (!psetstakey_para) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), + GFP_KERNEL); + if (!psetstakey_rsp) { + kfree(ph2c); + kfree(psetstakey_para); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, + _SetStaKey_CMD_); + ph2c->rsp = (u8 *) psetstakey_rsp; + ph2c->rspsz = sizeof(struct set_stakey_rsp); + + ether_addr_copy(psetstakey_para->addr, sta->hwaddr); + + psetstakey_para->algorithm = _NO_PRIVACY_; + + psetstakey_para->id = entry; + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + } +exit: + return res; +} + +u8 rtw_addbareq_cmd23a(struct rtw_adapter*padapter, u8 tid, u8 *addr) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct addBaReq_parm *paddbareq_parm; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC); + if (!paddbareq_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + paddbareq_parm->tid = tid; + ether_addr_copy(paddbareq_parm->addr, addr); + + init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, + GEN_CMD_CODE(_AddBAReq)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_dynamic_chk_wk_cmd23a(struct rtw_adapter*padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; + pdrvextra_cmd_parm->type_size = 0; + pdrvextra_cmd_parm->pbuf = (u8 *)padapter; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); +exit: + + return res; +} + +/* + * This is only ever called from on_action_spct23a_ch_switch () which isn't + * called from anywhere itself + */ +u8 rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, + u8 enqueue) +{ + struct cmd_obj *pcmdobj; + struct set_ch_parm *set_ch_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + DBG_8723A(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); + + /* check input parameter */ + + /* prepare cmd parameter */ + set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_KERNEL); + if (!set_ch_parm) { + res = _FAIL; + goto exit; + } + set_ch_parm->ch = ch; + set_ch_parm->bw = bw; + set_ch_parm->ch_offset = ch_offset; + + if (enqueue) { + /* need enqueue, prepare cmd_obj and enqueue */ + pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!pcmdobj) { + kfree(set_ch_parm); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, + GEN_CMD_CODE(_SetChannel)); + res = rtw_enqueue_cmd23a(pcmdpriv, pcmdobj); + } else { + /* no need to enqueue, do the cmd hdl directly and + free cmd parameter */ + if (H2C_SUCCESS != set_ch_hdl23a(padapter, (u8 *)set_ch_parm)) + res = _FAIL; + + kfree(set_ch_parm); + } + + /* do something based on res... */ +exit: + + DBG_8723A(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), + res); + + return res; +} + +static void traffic_status_watchdog(struct rtw_adapter *padapter) +{ + u8 bEnterPS; + u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false; + u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false; + u8 bHigherBusyTxTraffic = false; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + /* */ + /* Determine if our traffic is busy now */ + /* */ + if (check_fwstate(pmlmepriv, _FW_LINKED)) { +#ifdef CONFIG_8723AU_BT_COEXIST + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 50 || + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 50) +#else /* !CONFIG_8723AU_BT_COEXIST */ + /* if we raise bBusyTraffic in last watchdog, using + lower threshold. */ + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + BusyThreshold = 75; + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold || + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) +#endif /* !CONFIG_8723AU_BT_COEXIST */ + { + bBusyTraffic = true; + + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) + bRxBusyTraffic = true; + else + bTxBusyTraffic = true; + } + + /* Higher Tx/Rx data. */ + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) { + bHigherBusyTraffic = true; + + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) + bHigherBusyRxTraffic = true; + else + bHigherBusyTxTraffic = true; + } + +#ifdef CONFIG_8723AU_BT_COEXIST + if (BT_1Ant(padapter) == false) +#endif + { + /* check traffic for powersaving. */ + if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || + (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) + bEnterPS = false; + else + bEnterPS = true; + + /* LeisurePS only work in infra mode. */ + if (bEnterPS) + LPS_Enter23a(padapter); + else + LPS_Leave23a(padapter); + } + } else + LPS_Leave23a(padapter); + + pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; + pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; + pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; +} + +void dynamic_chk_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) +{ + struct mlme_priv *pmlmepriv; + + padapter = (struct rtw_adapter *)pbuf; + pmlmepriv = &padapter->mlmepriv; + +#ifdef CONFIG_8723AU_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + expire_timeout_chk23a(padapter); +#endif + + rtw_hal_sreset_xmit_status_check23a(padapter); + + linked_status_chk23a(padapter); + traffic_status_watchdog(padapter); + + rtw_hal_dm_watchdog23a(padapter); + +#ifdef CONFIG_8723AU_BT_COEXIST + /* */ + /* BT-Coexist */ + /* */ + BT_CoexistMechanism(padapter); +#endif +} + +void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 mstatus; + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) + return; + + switch (lps_ctrl_type) + { + case LPS_CTRL_SCAN: +#ifdef CONFIG_8723AU_BT_COEXIST + BT_WifiScanNotify(padapter, true); + if (BT_1Ant(padapter) == false) +#endif + { + if (check_fwstate(pmlmepriv, _FW_LINKED)) + LPS_Leave23a(padapter); + } + break; + case LPS_CTRL_JOINBSS: + LPS_Leave23a(padapter); + break; + case LPS_CTRL_CONNECT: + mstatus = 1;/* connect */ + /* Reset LPS Setting */ + padapter->pwrctrlpriv.LpsIdleCount = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&mstatus); +#ifdef CONFIG_8723AU_BT_COEXIST + BT_WifiMediaStatusNotify(padapter, mstatus); +#endif + break; + case LPS_CTRL_DISCONNECT: + mstatus = 0;/* disconnect */ +#ifdef CONFIG_8723AU_BT_COEXIST + BT_WifiMediaStatusNotify(padapter, mstatus); + if (BT_1Ant(padapter) == false) +#endif + { + LPS_Leave23a(padapter); + } + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&mstatus); + break; + case LPS_CTRL_SPECIAL_PACKET: + pwrpriv->DelayLPSLastTimeStamp = jiffies; +#ifdef CONFIG_8723AU_BT_COEXIST + BT_SpecialPacketNotify(padapter); + if (BT_1Ant(padapter) == false) +#endif + { + LPS_Leave23a(padapter); + } + break; + case LPS_CTRL_LEAVE: +#ifdef CONFIG_8723AU_BT_COEXIST + BT_LpsLeave(padapter); + if (BT_1Ant(padapter) == false) +#endif + { + LPS_Leave23a(padapter); + } + break; + + default: + break; + } +} + +u8 rtw_lps_ctrl_wk_cmd23a(struct rtw_adapter *padapter, + u8 lps_ctrl_type, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + if (enqueue) { + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), + GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; + pdrvextra_cmd_parm->type_size = lps_ctrl_type; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + } else + lps_ctrl_wk_hdl(padapter, lps_ctrl_type); +exit: + + return res; +} + +static void power_saving_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz) +{ + rtw_ps_processor23a(padapter); +} + +#ifdef CONFIG_8723AU_P2P +u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + { + return res; + } + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), + GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; + pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */ + pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */ + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); +exit: + + return res; +} +#endif /* CONFIG_8723AU_P2P */ + +u8 rtw_ps_cmd23a(struct rtw_adapter*padapter) +{ + struct cmd_obj *ppscmd; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ppscmd) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), + GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ppscmd); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; + pdrvextra_cmd_parm->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ppscmd); +exit: + + return res; +} + +#ifdef CONFIG_8723AU_AP_MODE + +static void rtw_chk_hi_queue_hdl(struct rtw_adapter *padapter) +{ + int cnt = 0; + struct sta_info *psta_bmc; + struct sta_priv *pstapriv = &padapter->stapriv; + + psta_bmc = rtw_get_bcmc_stainfo23a(padapter); + if (!psta_bmc) + return; + + if (psta_bmc->sleepq_len == 0) { + u8 val = 0; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); + + while(val == false) { + msleep(100); + + cnt++; + + if (cnt>10) + break; + + rtw23a_hal_get_hwreg(padapter, + HW_VAR_CHK_HI_QUEUE_EMPTY, &val); + } + + if (cnt <= 10) { + pstapriv->tim_bitmap &= ~BIT(0); + pstapriv->sta_dz_bitmap &= ~BIT(0); + + update_beacon23a(padapter, _TIM_IE_, NULL, false); + } else /* re check again */ + rtw_chk_hi_queue_cmd23a(padapter); + } +} + +u8 rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), + GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; + pdrvextra_cmd_parm->type_size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); +exit: + + return res; +} +#endif + +u8 rtw_c2h_wk_cmd23a(struct rtw_adapter *padapter, u8 *c2h_evt) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), + GFP_ATOMIC); + if (!pdrvextra_cmd_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = C2H_WK_CID; + pdrvextra_cmd_parm->type_size = c2h_evt?16:0; + pdrvextra_cmd_parm->pbuf = c2h_evt; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, + GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + +exit: + + return res; +} + +s32 c2h_evt_hdl(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt, + c2h_id_filter filter) +{ + s32 ret = _FAIL; + u8 buf[16]; + + if (!c2h_evt) { + /* No c2h event in cmd_obj, read c2h event before handling*/ + if (c2h_evt_read23a(adapter, buf) == _SUCCESS) { + c2h_evt = (struct c2h_evt_hdr *)buf; + + if (filter && filter(c2h_evt->id) == false) + goto exit; + + ret = rtw_hal_c2h_handler23a(adapter, c2h_evt); + } + } else { + + if (filter && filter(c2h_evt->id) == false) + goto exit; + + ret = rtw_hal_c2h_handler23a(adapter, c2h_evt); + } +exit: + return ret; +} + +static void c2h_wk_callback(struct work_struct *work) +{ + struct evt_priv *evtpriv; + struct rtw_adapter *adapter; + struct c2h_evt_hdr *c2h_evt; + c2h_id_filter ccx_id_filter; + + evtpriv = container_of(work, struct evt_priv, c2h_wk); + adapter = container_of(evtpriv, struct rtw_adapter, evtpriv); + ccx_id_filter = rtw_hal_c2h_id_filter_ccx23a(adapter); + + evtpriv->c2h_wk_alive = true; + + while (!rtw_cbuf_empty23a(evtpriv->c2h_queue)) { + c2h_evt = (struct c2h_evt_hdr *) + rtw_cbuf_pop23a(evtpriv->c2h_queue); + if (c2h_evt) { + /* This C2H event is read, clear it */ + c2h_evt_clear23a(adapter); + } else if ((c2h_evt = (struct c2h_evt_hdr *) + kmalloc(16, GFP_ATOMIC))) { + /* This C2H event is not read, read & clear now */ + if (c2h_evt_read23a(adapter, (u8*)c2h_evt) != _SUCCESS) + continue; + } + + /* Special pointer to trigger c2h_evt_clear23a only */ + if ((void *)c2h_evt == (void *)evtpriv) + continue; + + if (!c2h_evt_exist(c2h_evt)) { + kfree(c2h_evt); + continue; + } + + if (ccx_id_filter(c2h_evt->id) == true) { + /* Handle CCX report here */ + rtw_hal_c2h_handler23a(adapter, c2h_evt); + kfree(c2h_evt); + } else { + /* Enqueue into cmd_thread for others */ + rtw_c2h_wk_cmd23a(adapter, (u8 *)c2h_evt); + } + } + + evtpriv->c2h_wk_alive = false; +} + +u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct drvextra_cmd_parm *pdrvextra_cmd; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf; + + switch (pdrvextra_cmd->ec_id) + { + case DYNAMIC_CHK_WK_CID: + dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, + pdrvextra_cmd->type_size); + break; + case POWER_SAVING_CTRL_WK_CID: + power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, + pdrvextra_cmd->type_size); + break; + case LPS_CTRL_WK_CID: + lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size); + break; +#ifdef CONFIG_8723AU_P2P + case P2P_PS_WK_CID: + p2p_ps_wk_hdl23a(padapter, pdrvextra_cmd->type_size); + break; +#endif /* CONFIG_8723AU_P2P */ + case P2P_PROTO_WK_CID: + /* Commented by Albert 2011/07/01 */ + /* I used the type_size as the type command */ + p2p_protocol_wk_hdl23a(padapter, pdrvextra_cmd->type_size); + break; +#ifdef CONFIG_8723AU_AP_MODE + case CHECK_HIQ_WK_CID: + rtw_chk_hi_queue_hdl(padapter); + break; +#endif /* CONFIG_8723AU_AP_MODE */ + case C2H_WK_CID: + c2h_evt_hdl(padapter, + (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL); + break; + + default: + break; + } + + if (pdrvextra_cmd->pbuf && (pdrvextra_cmd->type_size > 0)) { + kfree(pdrvextra_cmd->pbuf); + pdrvextra_cmd->pbuf = NULL; + } + + return H2C_SUCCESS; +} + +void rtw_survey_cmd_callback23a(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res == H2C_DROPPED) { + /* TODO: cancel timer and do timeout handler directly... */ + /* need to make timeout handlerOS independent */ + mod_timer(&pmlmepriv->scan_to_timer, + jiffies + msecs_to_jiffies(1)); + } else if (pcmd->res != H2C_SUCCESS) { + mod_timer(&pmlmepriv->scan_to_timer, + jiffies + msecs_to_jiffies(1)); + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\n ********Error: MgntActrtw_set_802_11_bssid23a_" + "LIST_SCAN Fail ************\n\n.")); + } + + /* free cmd */ + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_disassoc_cmd23a_callback(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res != H2C_SUCCESS) { + spin_lock_bh(&pmlmepriv->lock); + set_fwstate(pmlmepriv, _FW_LINKED); + spin_unlock_bh(&pmlmepriv->lock); + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\n ***Error: disconnect_cmd_callback Fail ***\n.")); + return; + } + + /* free cmd */ + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_joinbss_cmd23a_callback(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (pcmd->res == H2C_DROPPED) { + /* TODO: cancel timer and do timeout handler directly... */ + /* need to make timeout handlerOS independent */ + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + } else if (pcmd->res != H2C_SUCCESS) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("********Error:rtw_select_and_join_from_scanned_" + "queue Wait Sema Fail ************\n")); + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + } + + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_createbss_cmd23a_callback(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct sta_info *psta; + struct wlan_network *pwlan; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + + if (pcmd->res != H2C_SUCCESS) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\n ********Error: rtw_createbss_cmd23a_callback " + "Fail ************\n\n.")); + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + } + + del_timer_sync(&pmlmepriv->assoc_timer); + + spin_lock_bh(&pmlmepriv->lock); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + psta = rtw_get_stainfo23a(&padapter->stapriv, + pnetwork->MacAddress); + if (!psta) { + psta = rtw_alloc_stainfo23a(&padapter->stapriv, + pnetwork->MacAddress); + if (!psta) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\nCan't alloc sta_info when " + "createbss_cmd_callback\n")); + goto createbss_cmd_fail ; + } + } + + rtw_indicate_connect23a(padapter); + } else { + pwlan = rtw_alloc_network(pmlmepriv); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + if (!pwlan) { + pwlan = rtw_get_oldest_wlan_network23a(&pmlmepriv->scanned_queue); + if (!pwlan) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\n Error: can't get pwlan in " + "rtw23a_joinbss_event_cb\n")); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + goto createbss_cmd_fail; + } + pwlan->last_scanned = jiffies; + } else { + list_add_tail(&pwlan->list, + &pmlmepriv->scanned_queue.queue); + } + + pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork); + memcpy(&pwlan->network, pnetwork, pnetwork->Length); + /* pwlan->fixed = true; */ + + /* list_add_tail(&pwlan->list, + &pmlmepriv->scanned_queue.queue); */ + + /* copy pdev_network information to + pmlmepriv->cur_network */ + memcpy(&tgt_network->network, pnetwork, + get_wlan_bssid_ex_sz(pnetwork)); + + /* reset DSConfig */ + + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + /* we will set _FW_LINKED when there is one more sat to + join us (rtw_stassoc_event_callback23a) */ + } + +createbss_cmd_fail: + + spin_unlock_bh(&pmlmepriv->lock); + + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_setstaKey_cmdrsp_callback23a(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct sta_priv *pstapriv; + struct set_stakey_rsp *psetstakey_rsp; + struct sta_info *psta; + + pstapriv = &padapter->stapriv; + psetstakey_rsp = (struct set_stakey_rsp*) (pcmd->rsp); + psta = rtw_get_stainfo23a(pstapriv, psetstakey_rsp->addr); + + if (!psta) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\nERROR: rtw_setstaKey_cmdrsp_callback23a => " + "can't get sta_info\n\n")); + goto exit; + } + +exit: + + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_setassocsta_cmdrsp_callback23a(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct set_assocsta_parm* passocsta_parm; + struct set_assocsta_rsp* passocsta_rsp; + struct sta_info *psta; + + passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); + passocsta_rsp = (struct set_assocsta_rsp*) (pcmd->rsp); + psta = rtw_get_stainfo23a(pstapriv, passocsta_parm->addr); + + if (psta == NULL) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, + ("\nERROR: setassocsta_cmdrsp_callbac => can't " + "get sta_info\n\n")); + goto exit; + } + + psta->aid = psta->mac_id = passocsta_rsp->cam_id; + + spin_lock_bh(&pmlmepriv->lock); + + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && + (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + set_fwstate(pmlmepriv, _FW_LINKED); + spin_unlock_bh(&pmlmepriv->lock); + +exit: + rtw_free_cmd_obj23a(pcmd); +} + +void rtw_getrttbl_cmd_cmdrsp_callback(struct rtw_adapter *padapter, + struct cmd_obj *pcmd) +{ + rtw_free_cmd_obj23a(pcmd); +} diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c new file mode 100644 index 000000000000..94221ee45bd2 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_efuse.c @@ -0,0 +1,718 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_EFUSE_C_ + +#include +#include + +#include + +/*------------------------Define local variable------------------------------*/ + +/* */ +#define REG_EFUSE_CTRL 0x0030 +#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ +/* */ + +/*----------------------------------------------------------------------------- + * Function: Efuse_PowerSwitch23a + * + * Overview: When we want to enable write operation, we should change to + * pwr on state. When we stop write, we should switch to 500k mode + * and disable LDO 2.5V. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/17/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void +Efuse_PowerSwitch23a( + struct rtw_adapter * pAdapter, + u8 bWrite, + u8 PwrState) +{ + pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState); +} + +/*----------------------------------------------------------------------------- + * Function: efuse_GetCurrentSize23a + * + * Overview: Get current efuse size!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +u16 +Efuse_GetCurrentSize23a(struct rtw_adapter *pAdapter, u8 efuseType) +{ + u16 ret = 0; + + ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType); + + return ret; +} + +/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ +u8 +Efuse_CalculateWordCnts23a(u8 word_en) +{ + u8 word_cnts = 0; + if (!(word_en & BIT(0))) word_cnts++; /* 0 : write enable */ + if (!(word_en & BIT(1))) word_cnts++; + if (!(word_en & BIT(2))) word_cnts++; + if (!(word_en & BIT(3))) word_cnts++; + return word_cnts; +} + +/* */ +/* Description: */ +/* Execute E-Fuse read byte operation. */ +/* Refered from SD1 Richard. */ +/* */ +/* Assumption: */ +/* 1. Boot from E-Fuse and successfully auto-load. */ +/* 2. PASSIVE_LEVEL (USB interface) */ +/* */ +/* Created by Roger, 2008.10.21. */ +/* */ +void +ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf) +{ + u32 value32; + u8 readbyte; + u16 retry; + /* u32 start = rtw_get_current_time(); */ + + /* Write Address */ + rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff)); + readbyte = rtw_read8(Adapter, EFUSE_CTRL+2); + rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + /* Write bit 32 0 */ + readbyte = rtw_read8(Adapter, EFUSE_CTRL+3); + rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f)); + + /* Check bit 32 read-ready */ + retry = 0; + value32 = rtw_read32(Adapter, EFUSE_CTRL); + /* while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) */ + while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) + { + value32 = rtw_read32(Adapter, EFUSE_CTRL); + retry++; + } + + /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ + /* This fix the problem that Efuse read error in high temperature condition. */ + /* Designer says that there shall be some delay after ready bit is set, or the */ + /* result will always stay on last data we read. */ + udelay(50); + value32 = rtw_read32(Adapter, EFUSE_CTRL); + + *pbuf = (u8)(value32 & 0xff); + /* DBG_8723A("ReadEFuseByte23a _offset:%08u, in %d ms\n", _offset , rtw_get_passing_time_ms23a(start)); */ +} + +/* */ +/* Description: */ +/* 1. Execute E-Fuse read byte operation according as map offset and */ +/* save to E-Fuse table. */ +/* 2. Refered from SD1 Richard. */ +/* */ +/* Assumption: */ +/* 1. Boot from E-Fuse and successfully auto-load. */ +/* 2. PASSIVE_LEVEL (USB interface) */ +/* */ +/* Created by Roger, 2008.10.21. */ +/* */ +/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ +/* 2. Add efuse utilization collect. */ +/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ +/* write addr must be after sec5. */ +/* */ + +void +efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType, + u16 _offset, u16 _size_byte, u8 *pbuf); +void +efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType, + u16 _offset, u16 _size_byte, u8 *pbuf) +{ + Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, + _size_byte, pbuf); +} + +void +EFUSE_GetEfuseDefinition23a(struct rtw_adapter *pAdapter, u8 efuseType, + u8 type, void *pOut) +{ + pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, + type, pOut); +} + +/*----------------------------------------------------------------------------- + * Function: EFUSE_Read1Byte23a + * + * Overview: Copy from WMAC fot EFUSE read 1 byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/23/2008 MHC Copy from WMAC. + * + *---------------------------------------------------------------------------*/ +u8 +EFUSE_Read1Byte23a(struct rtw_adapter *Adapter, u16 Address) +{ + u8 data; + u8 Bytetemp = {0x00}; + u8 temp = {0x00}; + u32 k = 0; + u16 contentLen = 0; + + EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI, + TYPE_EFUSE_REAL_CONTENT_LEN, + (void *)&contentLen); + + if (Address < contentLen) /* E-fuse 512Byte */ + { + /* Write E-fuse Register address bit0~7 */ + temp = Address & 0xFF; + rtw_write8(Adapter, EFUSE_CTRL+1, temp); + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); + /* Write E-fuse Register address bit8~9 */ + temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); + rtw_write8(Adapter, EFUSE_CTRL+2, temp); + + /* Write 0x30[31]= 0 */ + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + temp = Bytetemp & 0x7F; + rtw_write8(Adapter, EFUSE_CTRL+3, temp); + + /* Wait Write-ready (0x30[31]= 1) */ + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + while(!(Bytetemp & 0x80)) + { + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + k++; + if (k == 1000) + { + k = 0; + break; + } + } + data = rtw_read8(Adapter, EFUSE_CTRL); + return data; + } + else + return 0xFF; +}/* EFUSE_Read1Byte23a */ + +/*----------------------------------------------------------------------------- + * Function: EFUSE_Write1Byte + * + * Overview: Copy from WMAC fot EFUSE write 1 byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/23/2008 MHC Copy from WMAC. + * + *---------------------------------------------------------------------------*/ + +void +EFUSE_Write1Byte( + struct rtw_adapter * Adapter, + u16 Address, + u8 Value); +void +EFUSE_Write1Byte( + struct rtw_adapter * Adapter, + u16 Address, + u8 Value) +{ + u8 Bytetemp = {0x00}; + u8 temp = {0x00}; + u32 k = 0; + u16 contentLen = 0; + + /* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr =%x Data =%x\n", Address, Value)); */ + EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI, + TYPE_EFUSE_REAL_CONTENT_LEN, + (void *)&contentLen); + + if (Address < contentLen) /* E-fuse 512Byte */ + { + rtw_write8(Adapter, EFUSE_CTRL, Value); + + /* Write E-fuse Register address bit0~7 */ + temp = Address & 0xFF; + rtw_write8(Adapter, EFUSE_CTRL+1, temp); + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); + + /* Write E-fuse Register address bit8~9 */ + temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); + rtw_write8(Adapter, EFUSE_CTRL+2, temp); + + /* Write 0x30[31]= 1 */ + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + temp = Bytetemp | 0x80; + rtw_write8(Adapter, EFUSE_CTRL+3, temp); + + /* Wait Write-ready (0x30[31]= 0) */ + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + while(Bytetemp & 0x80) + { + Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); + k++; + if (k == 100) + { + k = 0; + break; + } + } + } +}/* EFUSE_Write1Byte */ + +/* 11/16/2008 MH Read one byte from real Efuse. */ +u8 +efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data) +{ + u8 tmpidx = 0; + u8 bResult; + + /* -----------------e-fuse reg ctrl --------------------------------- */ + /* address */ + rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); + rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03)) | + (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC)); + + rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */ + + while(!(0x80 &rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100)) + tmpidx++; + if (tmpidx < 100) { + *data = rtw_read8(pAdapter, EFUSE_CTRL); + bResult = true; + } else { + *data = 0xff; + bResult = false; + } + return bResult; +} + +/* 11/16/2008 MH Write one byte to reald Efuse. */ +u8 +efuse_OneByteWrite23a(struct rtw_adapter *pAdapter, u16 addr, u8 data) +{ + u8 tmpidx = 0; + u8 bResult; + + /* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr = %x Data =%x\n", addr, data)); */ + + /* return 0; */ + + /* -----------------e-fuse reg ctrl --------------------------------- */ + /* address */ + rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); + rtw_write8(pAdapter, EFUSE_CTRL+2, + (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC)|(u8)((addr>>8)&0x03)); + rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */ + + rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */ + + while((0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100)) { + tmpidx++; + } + + if (tmpidx<100) + { + bResult = true; + } + else + { + bResult = false; + } + + return bResult; +} + +int +Efuse_PgPacketRead23a(struct rtw_adapter *pAdapter, u8 offset, u8 *data) +{ + int ret = 0; + + ret = pAdapter->HalFunc.Efuse_PgPacketRead23a(pAdapter, offset, data); + + return ret; +} + +int +Efuse_PgPacketWrite23a(struct rtw_adapter *pAdapter, u8 offset, + u8 word_en, u8 *data) +{ + int ret; + + ret = pAdapter->HalFunc.Efuse_PgPacketWrite23a(pAdapter, offset, + word_en, data); + + return ret; +} + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataRead23a + * + * Overview: Read allowed word in current efuse section data. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * 11/21/2008 MHC Fix Write bug when we only enable late word. + * + *---------------------------------------------------------------------------*/ +void +efuse_WordEnableDataRead23a(u8 word_en, + u8 *sourdata, + u8 *targetdata) +{ + if (!(word_en&BIT(0))) + { + targetdata[0] = sourdata[0]; + targetdata[1] = sourdata[1]; + } + if (!(word_en&BIT(1))) + { + targetdata[2] = sourdata[2]; + targetdata[3] = sourdata[3]; + } + if (!(word_en&BIT(2))) + { + targetdata[4] = sourdata[4]; + targetdata[5] = sourdata[5]; + } + if (!(word_en&BIT(3))) + { + targetdata[6] = sourdata[6]; + targetdata[7] = sourdata[7]; + } +} + +u8 +Efuse_WordEnableDataWrite23a(struct rtw_adapter *pAdapter, u16 efuse_addr, + u8 word_en, u8 *data) +{ + u8 ret = 0; + + ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite23a(pAdapter, efuse_addr, + word_en, data); + + return ret; +} + +static u8 efuse_read8(struct rtw_adapter *padapter, u16 address, u8 *value) +{ + return efuse_OneByteRead23a(padapter, address, value); +} + +static u8 efuse_write8(struct rtw_adapter *padapter, u16 address, u8 *value) +{ + return efuse_OneByteWrite23a(padapter, address, *value); +} + +/* + * read/wirte raw efuse data + */ +u8 rtw_efuse_access23a(struct rtw_adapter *padapter, u8 bWrite, u16 start_addr, + u16 cnts, u8 *data) +{ + int i = 0; + u16 real_content_len = 0, max_available_size = 0; + u8 res = _FAIL ; + u8 (*rw8)(struct rtw_adapter *, u16, u8*); + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, + TYPE_EFUSE_REAL_CONTENT_LEN, + (void *)&real_content_len); + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, + (void *)&max_available_size); + + if (start_addr > real_content_len) + return _FAIL; + + if (true == bWrite) { + if ((start_addr + cnts) > max_available_size) + return _FAIL; + rw8 = &efuse_write8; + } else + rw8 = &efuse_read8; + + Efuse_PowerSwitch23a(padapter, bWrite, true); + + /* e-fuse one byte read / write */ + for (i = 0; i < cnts; i++) { + if (start_addr >= real_content_len) { + res = _FAIL; + break; + } + + res = rw8(padapter, start_addr++, data++); + if (_FAIL == res) break; + } + + Efuse_PowerSwitch23a(padapter, bWrite, false); + + return res; +} +/* */ +u16 efuse_GetMaxSize23a(struct rtw_adapter *padapter) +{ + u16 max_size; + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, + (void *)&max_size); + return max_size; +} +/* */ +u8 efuse_GetCurrentSize23a(struct rtw_adapter *padapter, u16 *size) +{ + Efuse_PowerSwitch23a(padapter, false, true); + *size = Efuse_GetCurrentSize23a(padapter, EFUSE_WIFI); + Efuse_PowerSwitch23a(padapter, false, false); + + return _SUCCESS; +} +/* */ +u8 rtw_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data) +{ + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, + TYPE_EFUSE_MAP_LEN, (void *)&mapLen); + + if ((addr + cnts) > mapLen) + return _FAIL; + + Efuse_PowerSwitch23a(padapter, false, true); + + efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data); + + Efuse_PowerSwitch23a(padapter, false, false); + + return _SUCCESS; +} + +u8 rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data) +{ + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT, + TYPE_EFUSE_MAP_LEN, (void *)&mapLen); + + if ((addr + cnts) > mapLen) + return _FAIL; + + Efuse_PowerSwitch23a(padapter, false, true); + + efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data); + + Efuse_PowerSwitch23a(padapter, false, false); + + return _SUCCESS; +} + +/*----------------------------------------------------------------------------- + * Function: Efuse_ReadAllMap + * + * Overview: Read All Efuse content + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/11/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void +Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse); +void +Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse) +{ + u16 mapLen = 0; + + Efuse_PowerSwitch23a(pAdapter, false, true); + + EFUSE_GetEfuseDefinition23a(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, + (void *)&mapLen); + + efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse); + + Efuse_PowerSwitch23a(pAdapter, false, false); +} + +/*----------------------------------------------------------------------------- + * Function: efuse_ShadowRead1Byte + * efuse_ShadowRead2Byte + * efuse_ShadowRead4Byte + * + * Overview: Read from efuse init map by one/two/four bytes !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +efuse_ShadowRead1Byte( + struct rtw_adapter * pAdapter, + u16 Offset, + u8 *Value) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); + + *Value = pEEPROM->efuse_eeprom_data[Offset]; +} /* EFUSE_ShadowRead23a1Byte */ + +/* Read Two Bytes */ +static void +efuse_ShadowRead2Byte( + struct rtw_adapter * pAdapter, + u16 Offset, + u16 *Value) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); + + *Value = pEEPROM->efuse_eeprom_data[Offset]; + *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; +} /* EFUSE_ShadowRead23a2Byte */ + +/* Read Four Bytes */ +static void +efuse_ShadowRead4Byte( + struct rtw_adapter * pAdapter, + u16 Offset, + u32 *Value) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); + + *Value = pEEPROM->efuse_eeprom_data[Offset]; + *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; + *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; + *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; +} /* efuse_ShadowRead4Byte */ + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowMapUpdate23a + * + * Overview: Transfer current EFUSE content to shadow init and modify map. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/13/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition23a(pAdapter, efuseType, + TYPE_EFUSE_MAP_LEN, (void *)&mapLen); + + if (pEEPROM->bautoload_fail_flag == true) + memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); + else + Efuse_ReadAllMap(pAdapter, efuseType, + pEEPROM->efuse_eeprom_data); + +}/* EFUSE_ShadowMapUpdate23a */ + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowRead23a + * + * Overview: Read from efuse init map !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void +EFUSE_ShadowRead23a( + struct rtw_adapter * pAdapter, + u8 Type, + u16 Offset, + u32 *Value ) +{ + if (Type == 1) + efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); + else if (Type == 2) + efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); + else if (Type == 4) + efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); +} /* EFUSE_ShadowRead23a */ diff --git a/drivers/staging/rtl8723au/core/rtw_ieee80211.c b/drivers/staging/rtl8723au/core/rtw_ieee80211.c new file mode 100644 index 000000000000..8287f447cbdd --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_ieee80211.c @@ -0,0 +1,1861 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _IEEE80211_C + +#include +#include +#include +#include +#include +#include + +u8 RTW_WPA_OUI23A_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; +u16 RTW_WPA_VERSION23A = 1; +u8 WPA_AUTH_KEY_MGMT_NONE23A[] = { 0x00, 0x50, 0xf2, 0 }; +u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X23A[] = { 0x00, 0x50, 0xf2, 1 }; +u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[] = { 0x00, 0x50, 0xf2, 2 }; +u8 WPA_CIPHER_SUITE_NONE23A[] = { 0x00, 0x50, 0xf2, 0 }; +u8 WPA_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x50, 0xf2, 1 }; +u8 WPA_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x50, 0xf2, 2 }; +u8 WPA_CIPHER_SUITE_WRAP23A[] = { 0x00, 0x50, 0xf2, 3 }; +u8 WPA_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x50, 0xf2, 4 }; +u8 WPA_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x50, 0xf2, 5 }; + +u16 RSN_VERSION_BSD23A = 1; +u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X23A[] = { 0x00, 0x0f, 0xac, 1 }; +u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[] = { 0x00, 0x0f, 0xac, 2 }; +u8 RSN_CIPHER_SUITE_NONE23A[] = { 0x00, 0x0f, 0xac, 0 }; +u8 RSN_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x0f, 0xac, 1 }; +u8 RSN_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x0f, 0xac, 2 }; +u8 RSN_CIPHER_SUITE_WRAP23A[] = { 0x00, 0x0f, 0xac, 3 }; +u8 RSN_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x0f, 0xac, 4 }; +u8 RSN_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x0f, 0xac, 5 }; +/* */ +/* for adhoc-master to generate ie and provide supported-rate to fw */ +/* */ + +static u8 WIFI_CCKRATES[] = +{(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)}; + +static u8 WIFI_OFDMRATES[] = +{(IEEE80211_OFDM_RATE_6MB), + (IEEE80211_OFDM_RATE_9MB), + (IEEE80211_OFDM_RATE_12MB), + (IEEE80211_OFDM_RATE_18MB), + (IEEE80211_OFDM_RATE_24MB), + IEEE80211_OFDM_RATE_36MB, + IEEE80211_OFDM_RATE_48MB, + IEEE80211_OFDM_RATE_54MB}; + +int rtw_get_bit_value_from_ieee_value23a(u8 val) +{ + unsigned char dot11_rate_table[]= + {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 0}; + + int i = 0; + while (dot11_rate_table[i] != 0) { + if (dot11_rate_table[i] == val) + return BIT(i); + i++; + } + return 0; +} + +uint rtw_is_cckrates_included23a(u8 *rate) +{ + u32 i = 0; + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || + (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) + return true; + i++; + } + + return false; +} + +uint rtw_is_cckratesonly_included23a(u8 *rate) +{ + u32 i = 0; + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && + (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) + return false; + + i++; + } + + return true; +} + +int rtw_check_network_type23a(unsigned char *rate, int ratelen, int channel) +{ + if (channel > 14) { + if ((rtw_is_cckrates_included23a(rate)) == true) + return WIRELESS_INVALID; + else + return WIRELESS_11A; + } else { /* could be pure B, pure G, or B/G */ + if ((rtw_is_cckratesonly_included23a(rate)) == true) + return WIRELESS_11B; + else if ((rtw_is_cckrates_included23a(rate)) == true) + return WIRELESS_11BG; + else + return WIRELESS_11G; + } +} + +u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len, + unsigned char *source, unsigned int *frlen) +{ + memcpy((void *)pbuf, (void *)source, len); + *frlen = *frlen + len; + return pbuf + len; +} + +/* rtw_set_ie23a will update frame length */ +u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen) +{ + + *pbuf = (u8)index; + + *(pbuf + 1) = (u8)len; + + if (len > 0) + memcpy((void *)(pbuf + 2), (void *)source, len); + + *frlen = *frlen + (len + 2); + + + return pbuf + len + 2; +} + +inline u8 *rtw_set_ie23a_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode, + u8 new_ch, u8 ch_switch_cnt) +{ + u8 ie_data[3]; + + ie_data[0] = ch_switch_mode; + ie_data[1] = new_ch; + ie_data[2] = ch_switch_cnt; + return rtw_set_ie23a(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len); +} + +inline u8 secondary_ch_offset_to_hal_ch_offset23a(u8 ch_offset) +{ + if (ch_offset == SCN) + return HAL_PRIME_CHNL_OFFSET_DONT_CARE; + else if (ch_offset == SCA) + return HAL_PRIME_CHNL_OFFSET_UPPER; + else if (ch_offset == SCB) + return HAL_PRIME_CHNL_OFFSET_LOWER; + + return HAL_PRIME_CHNL_OFFSET_DONT_CARE; +} + +inline u8 hal_ch_offset_to_secondary_ch_offset23a(u8 ch_offset) +{ + if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + return SCN; + else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + return SCB; + else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + return SCA; + + return SCN; +} + +inline u8 *rtw_set_ie23a_secondary_ch_offset(u8 *buf, u32 *buf_len, + u8 secondary_ch_offset) +{ + return rtw_set_ie23a(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, + 1, &secondary_ch_offset, buf_len); +} + +inline u8 *rtw_set_ie23a_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, + u8 flags, u16 reason, u16 precedence) +{ + u8 ie_data[6]; + + ie_data[0] = ttl; + ie_data[1] = flags; + RTW_PUT_LE16((u8*)&ie_data[2], reason); + RTW_PUT_LE16((u8*)&ie_data[4], precedence); + + return rtw_set_ie23a(buf, 0x118, 6, ie_data, buf_len); +} + +/*---------------------------------------------------------------------------- +index: the information element id index, limit is the limit for search +-----------------------------------------------------------------------------*/ +u8 *rtw_get_ie23a(u8 *pbuf, int index, int *len, int limit) +{ + int tmp, i; + u8 *p; + + if (limit < 1) { + + return NULL; + } + + p = pbuf; + i = 0; + *len = 0; + while (1) { + if (*p == index) { + *len = *(p + 1); + return p; + } else { + tmp = *(p + 1); + p += (tmp + 2); + i += (tmp + 2); + } + if (i >= limit) + break; + } + + return NULL; +} + +/** + * rtw_get_ie23a_ex - Search specific IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @eid: Element ID to match + * @oui: OUI to match + * @oui_len: OUI length + * @ie: If not NULL and the specific IE is found, the IE will be copied + * to the buf starting from the specific IE + * @ielen: If not NULL and the specific IE is found, will set to the length + * of the entire IE + * + * Returns: The address of the specific IE found, or NULL + */ +u8 *rtw_get_ie23a_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, + u8 *ie, uint *ielen) +{ + uint cnt; + u8 *target_ie = NULL; + + if (ielen) + *ielen = 0; + + if (!in_ie || in_len <= 0) + return target_ie; + + cnt = 0; + + while (cnt < in_len) { + if (eid == in_ie[cnt] && + (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) { + target_ie = &in_ie[cnt]; + + if (ie) + memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2); + + if (ielen) + *ielen = in_ie[cnt+1]+2; + break; + } else { + cnt += in_ie[cnt + 1] + 2; /* goto next */ + } + } + + return target_ie; +} + +/** + * rtw_ies_remove_ie23a - Find matching IEs and remove + * @ies: Address of IEs to search + * @ies_len: Pointer of length of ies, will update to new length + * @offset: The offset to start scarch + * @eid: Element ID to match + * @oui: OUI to match + * @oui_len: OUI length + * + * Returns: _SUCCESS: ies is updated, _FAIL: not updated + */ +int rtw_ies_remove_ie23a(u8 *ies, uint *ies_len, uint offset, u8 eid, + u8 *oui, u8 oui_len) +{ + int ret = _FAIL; + u8 *target_ie; + u32 target_ielen; + u8 *start; + uint search_len; + + if (!ies || !ies_len || *ies_len <= offset) + goto exit; + + start = ies + offset; + search_len = *ies_len - offset; + + while (1) { + target_ie = rtw_get_ie23a_ex(start, search_len, eid, oui, oui_len, + NULL, &target_ielen); + if (target_ie && target_ielen) { + u8 buf[MAX_IE_SZ] = {0}; + u8 *remain_ies = target_ie + target_ielen; + uint remain_len = search_len - (remain_ies - start); + + memcpy(buf, remain_ies, remain_len); + memcpy(target_ie, buf, remain_len); + *ies_len = *ies_len - target_ielen; + ret = _SUCCESS; + + start = target_ie; + search_len = remain_len; + } else { + break; + } + } +exit: + return ret; +} + +void rtw_set_supported_rate23a(u8* SupportedRates, uint mode) +{ + + + memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + + switch (mode) + { + case WIRELESS_11B: + memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + break; + + case WIRELESS_11G: + case WIRELESS_11A: + case WIRELESS_11_5N: + case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */ + memcpy(SupportedRates, WIFI_OFDMRATES, + IEEE80211_NUM_OFDM_RATESLEN); + break; + + case WIRELESS_11BG: + case WIRELESS_11G_24N: + case WIRELESS_11_24N: + case WIRELESS_11BG_24N: + memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, + IEEE80211_NUM_OFDM_RATESLEN); + break; + } + +} + +uint rtw_get_rateset_len23a(u8 *rateset) +{ + uint i = 0; + + while(1) { + if ((rateset[i]) == 0) + break; + + if (i > 12) + break; + + i++; + } + + return i; +} + +int rtw_generate_ie23a(struct registry_priv *pregistrypriv) +{ + u8 wireless_mode; + int sz = 0, rateLen; + struct wlan_bssid_ex* pdev_network = &pregistrypriv->dev_network; + u8* ie = pdev_network->IEs; + + + + /* timestamp will be inserted by hardware */ + sz += 8; + ie += sz; + + /* beacon interval : 2bytes */ + /* BCN_INTERVAL; */ + *(u16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod); + sz += 2; + ie += 2; + + /* capability info */ + *(u16*)ie = 0; + + *(u16*)ie |= cpu_to_le16(cap_IBSS); + + if (pregistrypriv->preamble == PREAMBLE_SHORT) + *(u16*)ie |= cpu_to_le16(cap_ShortPremble); + + if (pdev_network->Privacy) + *(u16*)ie |= cpu_to_le16(cap_Privacy); + + sz += 2; + ie += 2; + + /* SSID */ + ie = rtw_set_ie23a(ie, _SSID_IE_, pdev_network->Ssid.ssid_len, + pdev_network->Ssid.ssid, &sz); + + /* supported rates */ + if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) { + if (pdev_network->Configuration.DSConfig > 14) + wireless_mode = WIRELESS_11A_5N; + else + wireless_mode = WIRELESS_11BG_24N; + } else { + wireless_mode = pregistrypriv->wireless_mode; + } + + rtw_set_supported_rate23a(pdev_network->SupportedRates, wireless_mode) ; + + rateLen = rtw_get_rateset_len23a(pdev_network->SupportedRates); + + if (rateLen > 8) { + ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, 8, + pdev_network->SupportedRates, &sz); + /* ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ + } else { + ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, rateLen, + pdev_network->SupportedRates, &sz); + } + + /* DS parameter set */ + ie = rtw_set_ie23a(ie, _DSSET_IE_, 1, + (u8 *)&pdev_network->Configuration.DSConfig, &sz); + + /* IBSS Parameter Set */ + + ie = rtw_set_ie23a(ie, _IBSS_PARA_IE_, 2, + (u8 *)&pdev_network->Configuration.ATIMWindow, &sz); + + if (rateLen > 8) { + ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), + (pdev_network->SupportedRates + 8), &sz); + } + + + + /* return _SUCCESS; */ + + return sz; +} + +unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit) +{ + int len; + u16 val16; + unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; + u8 *pbuf = pie; + int limit_new = limit; + + while(1) { + pbuf = rtw_get_ie23a(pbuf, _WPA_IE_ID_, &len, limit_new); + + if (pbuf) { + /* check if oui matches... */ + if (memcmp((pbuf + 2), wpa_oui_type, + sizeof(wpa_oui_type))) { + goto check_next_ie; + } + + /* check version... */ + memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); + + val16 = le16_to_cpu(val16); + if (val16 != 0x0001) + goto check_next_ie; + + *wpa_ie_len = *(pbuf + 1); + + return pbuf; + } else { + *wpa_ie_len = 0; + return NULL; + } + +check_next_ie: + + limit_new = limit - (pbuf - pie) - 2 - len; + + if (limit_new <= 0) + break; + + pbuf += (2 + len); + } + + *wpa_ie_len = 0; + + return NULL; +} + +unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit) +{ + return rtw_get_ie23a(pie, _WPA2_IE_ID_, rsn_ie_len, limit); +} + +int rtw_get_wpa_cipher_suite23a(u8 *s) +{ + if (!memcmp(s, WPA_CIPHER_SUITE_NONE23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, WPA_CIPHER_SUITE_WEP4023A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, WPA_CIPHER_SUITE_TKIP23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, WPA_CIPHER_SUITE_CCMP23A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, WPA_CIPHER_SUITE_WEP10423A, WPA_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + + return 0; +} + +int rtw_get_wpa2_cipher_suite23a(u8 *s) +{ + if (!memcmp(s, RSN_CIPHER_SUITE_NONE23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_NONE; + if (!memcmp(s, RSN_CIPHER_SUITE_WEP4023A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP40; + if (!memcmp(s, RSN_CIPHER_SUITE_TKIP23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_TKIP; + if (!memcmp(s, RSN_CIPHER_SUITE_CCMP23A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_CCMP; + if (!memcmp(s, RSN_CIPHER_SUITE_WEP10423A, RSN_SELECTOR_LEN)) + return WPA_CIPHER_WEP104; + + return 0; +} + +int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) +{ + int i, ret = _SUCCESS; + int left, count; + u8 *pos; + u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; + + if (wpa_ie_len <= 0) { + /* No WPA IE - fail silently */ + return _FAIL; + } + + if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) || + memcmp(wpa_ie + 2, RTW_WPA_OUI23A_TYPE, WPA_SELECTOR_LEN)) { + return _FAIL; + } + + pos = wpa_ie; + + pos += 8; + left = wpa_ie_len - 8; + + /* group_cipher */ + if (left >= WPA_SELECTOR_LEN) { + + *group_cipher = rtw_get_wpa_cipher_suite23a(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } else if (left > 0) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie length mismatch, %u too much", + __func__, left)); + + return _FAIL; + } + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(u16*)pos); */ + count = RTW_GET_LE16(pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie count botch (pairwise), " + "count %u left %u", __func__, + count, left)); + return _FAIL; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= rtw_get_wpa_cipher_suite23a(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie too short (for key mgmt)", __func__)); + return _FAIL; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (!memcmp(pos, SUITE_1X, 4)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s : there has 802.1x auth\n", + __func__)); + *is_8021x = 1; + } + } + } + + return ret; +} + +int rtw_parse_wpa2_ie23a(u8* rsn_ie, int rsn_ie_len, int *group_cipher, + int *pairwise_cipher, int *is_8021x) +{ + int i, ret = _SUCCESS; + int left, count; + u8 *pos; + u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; + + if (rsn_ie_len <= 0) { + /* No RSN IE - fail silently */ + return _FAIL; + } + + if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) { + return _FAIL; + } + + pos = rsn_ie; + pos += 4; + left = rsn_ie_len - 4; + + /* group_cipher */ + if (left >= RSN_SELECTOR_LEN) { + *group_cipher = rtw_get_wpa2_cipher_suite23a(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } else if (left > 0) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie length mismatch, %u too much", + __func__, left)); + return _FAIL; + } + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(u16*)pos); */ + count = RTW_GET_LE16(pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie count botch (pairwise), " + "count %u left %u", + __func__, count, left)); + return _FAIL; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= rtw_get_wpa2_cipher_suite23a(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s: ie too short (for key mgmt)", __func__)); + + return _FAIL; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (!memcmp(pos, SUITE_1X, 4)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s (): there has 802.1x auth\n", + __func__)); + *is_8021x = 1; + } + } + } + + return ret; +} + +int rtw_get_sec_ie23a(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, + u8 *wpa_ie, u16 *wpa_len) +{ + u8 authmode, sec_idx, i; + u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; + uint cnt; + + + + /* Search required WPA or WPA2 IE and copy to sec_ie[ ] */ + + cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); + + sec_idx = 0; + + while(cnt < in_len) { + authmode = in_ie[cnt]; + + if ((authmode == _WPA_IE_ID_) && + !memcmp(&in_ie[cnt+2], &wpa_oui[0], 4)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("\n rtw_get_wpa_ie23a: sec_idx =%d " + "in_ie[cnt+1]+2 =%d\n", + sec_idx, in_ie[cnt + 1] + 2)); + + if (wpa_ie) { + memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2); + + for (i = 0; i < (in_ie[cnt + 1] + 2); i = i + 8) { + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_info_, + ("\n %2x,%2x,%2x,%2x,%2x,%2x," + "%2x,%2x\n", wpa_ie[i], + wpa_ie[i + 1], wpa_ie[i + 2], + wpa_ie[i + 3], wpa_ie[i + 4], + wpa_ie[i + 5], wpa_ie[i + 6], + wpa_ie[i + 7])); + } + } + + *wpa_len = in_ie[cnt + 1] + 2; + cnt += in_ie[cnt + 1] + 2; /* get next */ + } else { + if (authmode == _WPA2_IE_ID_) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("\n get_rsn_ie: sec_idx =%d in_ie" + "[cnt+1]+2 =%d\n", sec_idx, + in_ie[cnt + 1] + 2)); + + if (rsn_ie) { + memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + for (i = 0; i < (in_ie[cnt + 1] + 2); i = i + 8) { + RT_TRACE(_module_rtl871x_mlme_c_, + _drv_info_, + ("\n %2x,%2x,%2x,%2x,%2x,%2x," + "%2x,%2x\n", rsn_ie[i], + rsn_ie[i + 1], rsn_ie[i + 2], + rsn_ie[i + 3], rsn_ie[i + 4], + rsn_ie[i + 5], rsn_ie[i + 6], + rsn_ie[i + 7])); + } + } + + *rsn_len = in_ie[cnt + 1] + 2; + cnt += in_ie[cnt + 1] + 2; /* get next */ + } else { + cnt += in_ie[cnt + 1] + 2; /* get next */ + } + } + } + + + + return *rsn_len + *wpa_len; +} + +u8 rtw_is_wps_ie23a(u8 *ie_ptr, uint *wps_ielen) +{ + u8 match = false; + u8 eid, wps_oui[4]= {0x0, 0x50, 0xf2, 0x04}; + + if (!ie_ptr) + return match; + + eid = ie_ptr[0]; + + if ((eid == _WPA_IE_ID_) && !memcmp(&ie_ptr[2], wps_oui, 4)) { + /* DBG_8723A("==> found WPS_IE.....\n"); */ + *wps_ielen = ie_ptr[1] + 2; + match = true; + } + return match; +} + +/** + * rtw_get_wps_ie23a - Search WPS IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the + * buf starting from wps_ie + * @wps_ielen: If not NULL and WPS IE is found, will set to the length of + * the entire WPS IE + * + * Returns: The address of the WPS IE found, or NULL + */ +u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) +{ + uint cnt; + u8 *wpsie_ptr = NULL; + u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + + if (wps_ielen) + *wps_ielen = 0; + + if (!in_ie || in_len <= 0) + return wpsie_ptr; + + cnt = 0; + + while (cnt < in_len) { + eid = in_ie[cnt]; + + if ((eid == _WPA_IE_ID_) && !memcmp(&in_ie[cnt+2], wps_oui, 4)) { + wpsie_ptr = &in_ie[cnt]; + + if (wps_ie) + memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (wps_ielen) + *wps_ielen = in_ie[cnt + 1] + 2; + + cnt += in_ie[cnt + 1] + 2; + + break; + } else { + cnt += in_ie[cnt + 1] + 2; /* goto next */ + } + } + + return wpsie_ptr; +} + +/** + * rtw_get_wps_attr23a - Search a specific WPS attribute from a given WPS IE + * @wps_ie: Address of WPS IE to search + * @wps_ielen: Length limit from wps_ie + * @target_attr_id: The attribute ID of WPS attribute to search + * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute + * will be copied to the buf starting from buf_attr + * @len_attr: If not NULL and the WPS attribute is found, will set to the + * length of the entire WPS attribute + * + * Returns: the address of the specific WPS attribute found, or NULL + */ +u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, + u8 *buf_attr, u32 *len_attr) +{ + u8 *attr_ptr = NULL; + u8 * target_attr_ptr = NULL; + u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04}; + + if (len_attr) + *len_attr = 0; + + if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) || + memcmp(wps_ie + 2, wps_oui, 4)) { + return attr_ptr; + } + + /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */ + attr_ptr = wps_ie + 6; /* goto first attr */ + + while (attr_ptr - wps_ie < wps_ielen) { + /* 4 = 2(Attribute ID) + 2(Length) */ + u16 attr_id = RTW_GET_BE16(attr_ptr); + u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2); + u16 attr_len = attr_data_len + 4; + + /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ + if (attr_id == target_attr_id) { + target_attr_ptr = attr_ptr; + + if (buf_attr) + memcpy(buf_attr, attr_ptr, attr_len); + + if (len_attr) + *len_attr = attr_len; + + break; + } else { + attr_ptr += attr_len; /* goto next */ + } + } + + return target_attr_ptr; +} + +/** + * rtw_get_wps_attr_content23a - Search a specific WPS attribute content + * from a given WPS IE + * @wps_ie: Address of WPS IE to search + * @wps_ielen: Length limit from wps_ie + * @target_attr_id: The attribute ID of WPS attribute to search + * @buf_content: If not NULL and the WPS attribute is found, WPS attribute + * content will be copied to the buf starting from buf_content + * @len_content: If not NULL and the WPS attribute is found, will set to the + * length of the WPS attribute content + * + * Returns: the address of the specific WPS attribute content found, or NULL + */ +u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, + u8 *buf_content, uint *len_content) +{ + u8 *attr_ptr; + u32 attr_len; + + if (len_content) + *len_content = 0; + + attr_ptr = rtw_get_wps_attr23a(wps_ie, wps_ielen, target_attr_id, + NULL, &attr_len); + + if (attr_ptr && attr_len) { + if (buf_content) + memcpy(buf_content, attr_ptr + 4, attr_len - 4); + + if (len_content) + *len_content = attr_len - 4; + + return attr_ptr + 4; + } + + return NULL; +} + +static int +rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, + struct rtw_ieee802_11_elems *elems, + int show_errors) +{ + unsigned int oui; + + /* first 3 bytes in vendor specific information element are the IEEE + * OUI of the vendor. The following byte is used a vendor specific + * sub-type. */ + if (elen < 4) { + if (show_errors) { + DBG_8723A("short vendor specific " + "information element ignored (len =%lu)\n", + (unsigned long) elen); + } + return -1; + } + + oui = RTW_GET_BE24(pos); + switch (oui) { + case WLAN_OUI_MICROSOFT: + /* Microsoft/Wi-Fi information elements are further typed and + * subtyped */ + switch (pos[3]) { + case 1: + /* Microsoft OUI (00:50:F2) with OUI Type 1: + * real WPA information element */ + elems->wpa_ie = pos; + elems->wpa_ie_len = elen; + break; + case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ + if (elen < 5) { + DBG_8723A("short WME " + "information element ignored " + "(len =%lu)\n", + (unsigned long) elen); + return -1; + } + switch (pos[4]) { + case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: + case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: + elems->wme = pos; + elems->wme_len = elen; + break; + case WME_OUI_SUBTYPE_TSPEC_ELEMENT: + elems->wme_tspec = pos; + elems->wme_tspec_len = elen; + break; + default: + DBG_8723A("unknown WME " + "information element ignored " + "(subtype =%d len =%lu)\n", + pos[4], (unsigned long) elen); + return -1; + } + break; + case 4: + /* Wi-Fi Protected Setup (WPS) IE */ + elems->wps_ie = pos; + elems->wps_ie_len = elen; + break; + default: + DBG_8723A("Unknown Microsoft " + "information element ignored " + "(type =%d len =%lu)\n", + pos[3], (unsigned long) elen); + return -1; + } + break; + + case OUI_BROADCOM: + switch (pos[3]) { + case VENDOR_HT_CAPAB_OUI_TYPE: + elems->vendor_ht_cap = pos; + elems->vendor_ht_cap_len = elen; + break; + default: + DBG_8723A("Unknown Broadcom " + "information element ignored " + "(type =%d len =%lu)\n", + pos[3], (unsigned long) elen); + return -1; + } + break; + + default: + DBG_8723A("unknown vendor specific information " + "element ignored (vendor OUI %02x:%02x:%02x " + "len =%lu)\n", + pos[0], pos[1], pos[2], (unsigned long) elen); + return -1; + } + + return 0; +} + +/** + * ieee802_11_parse_elems - Parse information elements in management frames + * @start: Pointer to the start of IEs + * @len: Length of IE buffer in octets + * @elems: Data structure for parsed elements + * @show_errors: Whether to show parsing errors in debug log + * Returns: Parsing result + */ +enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len, + struct rtw_ieee802_11_elems *elems, + int show_errors) +{ + uint left = len; + u8 *pos = start; + int unknown = 0; + + memset(elems, 0, sizeof(*elems)); + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) { + if (show_errors) { + DBG_8723A("IEEE 802.11 element " + "parse failed (id =%d elen =%d " + "left =%lu)\n", + id, elen, (unsigned long) left); + } + return ParseFailed; + } + + switch (id) { + case WLAN_EID_SSID: + elems->ssid = pos; + elems->ssid_len = elen; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = pos; + elems->supp_rates_len = elen; + break; + case WLAN_EID_FH_PARAMS: + elems->fh_params = pos; + elems->fh_params_len = elen; + break; + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_CF_PARAMS: + elems->cf_params = pos; + elems->cf_params_len = elen; + break; + case WLAN_EID_TIM: + elems->tim = pos; + elems->tim_len = elen; + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_CHALLENGE: + elems->challenge = pos; + elems->challenge_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = pos; + elems->ext_supp_rates_len = elen; + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (rtw_ieee802_11_parse_vendor_specific(pos, elen, + elems, + show_errors)) + unknown++; + break; + case WLAN_EID_RSN: + elems->rsn_ie = pos; + elems->rsn_ie_len = elen; + break; + case WLAN_EID_PWR_CAPABILITY: + elems->power_cap = pos; + elems->power_cap_len = elen; + break; + case WLAN_EID_SUPPORTED_CHANNELS: + elems->supp_channels = pos; + elems->supp_channels_len = elen; + break; + case WLAN_EID_MOBILITY_DOMAIN: + elems->mdie = pos; + elems->mdie_len = elen; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + elems->ftie = pos; + elems->ftie_len = elen; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + elems->timeout_int = pos; + elems->timeout_int_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + elems->ht_capabilities = pos; + elems->ht_capabilities_len = elen; + break; + case WLAN_EID_HT_OPERATION: + elems->ht_operation = pos; + elems->ht_operation_len = elen; + break; + default: + unknown++; + if (!show_errors) + break; + DBG_8723A("IEEE 802.11 element parse " + "ignored unknown element (id =%d elen =%d)\n", + id, elen); + break; + } + + left -= elen; + pos += elen; + } + + if (left) + return ParseFailed; + + return unknown ? ParseUnknown : ParseOK; +} + +static u8 key_char2num(u8 ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + else if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + else if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + else + return 0xff; +} + +u8 str_2char2num23a(u8 hch, u8 lch) +{ + return (key_char2num(hch) * 10) + key_char2num(lch); +} + +u8 key_2char2num23a(u8 hch, u8 lch) +{ + return (key_char2num(hch) << 4) | key_char2num(lch); +} + +void rtw_macaddr_cfg23a(u8 *mac_addr) +{ + u8 mac[ETH_ALEN]; + if (!mac_addr) + return; + + memcpy(mac, mac_addr, ETH_ALEN); + + if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) { + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0x4c; + mac[3] = 0x87; + mac[4] = 0x00; + mac[5] = 0x00; + /* use default mac addresss */ + memcpy(mac_addr, mac, ETH_ALEN); + DBG_8723A("MAC Address from efuse error, assign default " + "one !!!\n"); + } + DBG_8723A("rtw_macaddr_cfg23a MAC Address = "MAC_FMT"\n", + MAC_ARG(mac_addr)); +} + +void dump_ies23a(u8 *buf, u32 buf_len) { + u8* pos = (u8*)buf; + u8 id, len; + + while (pos-buf <= buf_len) { + id = *pos; + len = *(pos + 1); + + DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len); +#ifdef CONFIG_8723AU_P2P + dump_p2p_ie23a(pos, len); +#endif + dump_wps_ie23a(pos, len); + + pos += (2 + len); + } +} + +void dump_wps_ie23a(u8 *ie, u32 ie_len) { + u8* pos = (u8*)ie; + u16 id; + u16 len; + + u8 *wps_ie; + uint wps_ielen; + + wps_ie = rtw_get_wps_ie23a(ie, ie_len, NULL, &wps_ielen); + if (wps_ie != ie || wps_ielen == 0) + return; + + pos+= 6; + while (pos-ie < ie_len) { + id = RTW_GET_BE16(pos); + len = RTW_GET_BE16(pos + 2); + + DBG_8723A("%s ID:0x%04x, LEN:%u\n", __func__, id, len); + + pos += (4 + len); + } +} + +#ifdef CONFIG_8723AU_P2P +void dump_p2p_ie23a(u8 *ie, u32 ie_len) { + u8* pos = (u8*)ie; + u8 id; + u16 len; + + u8 *p2p_ie; + uint p2p_ielen; + + p2p_ie = rtw_get_p2p_ie23a(ie, ie_len, NULL, &p2p_ielen); + if (p2p_ie != ie || p2p_ielen == 0) + return; + + pos += 6; + while (pos-ie < ie_len) { + id = *pos; + len = RTW_GET_LE16(pos+1); + + DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len); + + pos+= (3+len); + } +} + +/** + * rtw_get_p2p_ie23a - Search P2P IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the + * buf starting from p2p_ie + * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of + * the entire P2P IE + * + * Returns: The address of the P2P IE found, or NULL + */ +u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) +{ + uint cnt = 0; + u8 *p2p_ie_ptr; + u8 eid, p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09}; + + if (p2p_ielen) + *p2p_ielen = 0; + + while (cnt MAX_IE_SZ)) { + dump_stack(); + return NULL; + } + if ((eid == _VENDOR_SPECIFIC_IE_) && + !memcmp(&in_ie[cnt + 2], p2p_oui, 4)) { + p2p_ie_ptr = in_ie + cnt; + + if (p2p_ie != NULL) { + memcpy(p2p_ie, &in_ie[cnt], + in_ie[cnt + 1] + 2); + } + + if (p2p_ielen != NULL) { + *p2p_ielen = in_ie[cnt + 1] + 2; + } + + return p2p_ie_ptr; + + break; + } else { + cnt += in_ie[cnt + 1] + 2; /* goto next */ + } + } + + return NULL; +} + +/** + * rtw_get_p2p_attr23a - Search a specific P2P attribute from a given P2P IE + * @p2p_ie: Address of P2P IE to search + * @p2p_ielen: Length limit from p2p_ie + * @target_attr_id: The attribute ID of P2P attribute to search + * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will + * be copied to the buf starting from buf_attr + * @len_attr: If not NULL and the P2P attribute is found, will set to the + * length of the entire P2P attribute + * + * Returns: the address of the specific WPS attribute found, or NULL + */ +u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, + u8 *buf_attr, u32 *len_attr) +{ + u8 *attr_ptr = NULL; + u8 *target_attr_ptr = NULL; + u8 p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09}; + + if (len_attr) + *len_attr = 0; + + if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) || + memcmp(p2p_ie + 2, p2p_oui, 4)) { + return attr_ptr; + } + + /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ + attr_ptr = p2p_ie + 6; /* goto first attr */ + + while (attr_ptr - p2p_ie < p2p_ielen) { + /* 3 = 1(Attribute ID) + 2(Length) */ + u8 attr_id = *attr_ptr; + u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1); + u16 attr_len = attr_data_len + 3; + + /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ + if (attr_id == target_attr_id) { + target_attr_ptr = attr_ptr; + + if (buf_attr) + memcpy(buf_attr, attr_ptr, attr_len); + + if (len_attr) + *len_attr = attr_len; + + break; + } else { + attr_ptr += attr_len; /* goto next */ + } + } + + return target_attr_ptr; +} + +/** + * rtw_get_p2p_attr23a_content - Search a specific P2P attribute content from + * a given P2P IE + * @p2p_ie: Address of P2P IE to search + * @p2p_ielen: Length limit from p2p_ie + * @target_attr_id: The attribute ID of P2P attribute to search + * @buf_content: If not NULL and the P2P attribute is found, P2P attribute + * content will be copied to the buf starting from buf_content + * @len_content: If not NULL and the P2P attribute is found, will set to the + * length of the P2P attribute content + * + * Returns: the address of the specific P2P attribute content found, or NULL + */ +u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, + u8 *buf_content, uint *len_content) +{ + u8 *attr_ptr; + u32 attr_len; + + if (len_content) + *len_content = 0; + + attr_ptr = rtw_get_p2p_attr23a(p2p_ie, p2p_ielen, target_attr_id, + NULL, &attr_len); + + if (attr_ptr && attr_len) { + if (buf_content) + memcpy(buf_content, attr_ptr + 3, attr_len - 3); + + if (len_content) + *len_content = attr_len - 3; + + return attr_ptr+3; + } + + return NULL; +} + +u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) +{ + u32 a_len; + + *pbuf = attr_id; + + /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ + RTW_PUT_LE16(pbuf + 1, attr_len); + + if (pdata_attr) + memcpy(pbuf + 3, pdata_attr, attr_len); + + a_len = attr_len + 3; + + return a_len; +} + +static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id) +{ + u8 *target_attr; + u32 target_attr_len; + uint ielen = ielen_ori; + + while(1) { + target_attr = rtw_get_p2p_attr23a(ie, ielen, attr_id, NULL, + &target_attr_len); + if (target_attr && target_attr_len) { + u8 *next_attr = target_attr+target_attr_len; + uint remain_len = ielen-(next_attr-ie); + /* dump_ies23a(ie, ielen); */ + + memset(target_attr, 0, target_attr_len); + memcpy(target_attr, next_attr, remain_len); + memset(target_attr+remain_len, 0, target_attr_len); + *(ie + 1) -= target_attr_len; + ielen -= target_attr_len; + } else { + /* if (index>0) */ + /* dump_ies23a(ie, ielen); */ + break; + } + } + + return ielen; +} + +void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id) +{ + u8 *p2p_ie; + uint p2p_ielen, p2p_ielen_ori; + + if ((p2p_ie = rtw_get_p2p_ie23a(bss_ex->IEs + _FIXED_IE_LENGTH_, + bss_ex->IELength - _FIXED_IE_LENGTH_, + NULL, &p2p_ielen_ori))) { + p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id); + if (p2p_ielen != p2p_ielen_ori) { + u8 *next_ie_ori = p2p_ie+p2p_ielen_ori; + u8 *next_ie = p2p_ie+p2p_ielen; + uint remain_len; + remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs); + + memcpy(next_ie, next_ie_ori, remain_len); + memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen); + bss_ex->IELength -= p2p_ielen_ori-p2p_ielen; + } + } +} + +#endif /* CONFIG_8723AU_P2P */ + +#ifdef CONFIG_8723AU_P2P +int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen) +{ + int match; + uint cnt = 0; + u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; + + match = false; + + if (in_len < 0) { + return match; + } + + while (cnt < in_len) + { + eid = in_ie[cnt]; + + if ((eid == _VENDOR_SPECIFIC_IE_) && + !memcmp(&in_ie[cnt+2], wfd_oui, 4)) { + if (wfd_ie != NULL) { + memcpy(wfd_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + } else { + if (wfd_ielen != NULL) { + *wfd_ielen = 0; + } + } + + if (wfd_ielen != NULL) { + *wfd_ielen = in_ie[cnt + 1] + 2; + } + + cnt += in_ie[cnt + 1] + 2; + + match = true; + break; + } else { + cnt += in_ie[cnt + 1] +2; /* goto next */ + } + } + + if (match == true) { + match = cnt; + } + + return match; +} + +/* attr_content: The output buffer, contains the "body field" of + WFD attribute. */ +/* attr_contentlen: The data length of the "body field" of WFD + attribute. */ +int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, + u8 *attr_content, uint *attr_contentlen) +{ + int match; + uint cnt = 0; + u8 attr_id, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; + + match = false; + + if ((wfd_ie[0] != _VENDOR_SPECIFIC_IE_) || + memcmp(wfd_ie + 2, wfd_oui, 4)) { + return match; + } + + /* 1 (WFD IE) + 1 (Length) + 3 (OUI) + 1 (OUI Type) */ + cnt = 6; + while (cnt < wfd_ielen) { + u16 attrlen = RTW_GET_BE16(wfd_ie + cnt + 1); + + attr_id = wfd_ie[cnt]; + if (attr_id == target_attr_id) { + /* 3 -> 1 byte for attribute ID field, 2 + bytes for length field */ + if (attr_content) + memcpy(attr_content, &wfd_ie[cnt + 3], attrlen); + + if (attr_contentlen) + *attr_contentlen = attrlen; + + cnt += attrlen + 3; + + match = true; + break; + } else { + cnt += attrlen + 3; /* goto next */ + } + } + + return match; +} +#endif /* CONFIG_8723AU_P2P */ + +/* Baron adds to avoid FreeBSD warning */ +int ieee80211_is_empty_essid23a(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static int rtw_get_cipher_info(struct wlan_network *pnetwork) +{ + u32 wpa_ielen; + unsigned char *pbuf; + int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; + int ret = _FAIL; + int r; + pbuf = rtw_get_wpa_ie23a(&pnetwork->network.IEs[12], &wpa_ielen, + pnetwork->network.IELength - 12); + + if (pbuf && (wpa_ielen > 0)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); + r = rtw_parse_wpa_ie23a(pbuf, wpa_ielen + 2, &group_cipher, + &pairwise_cipher, &is8021x); + if (r == _SUCCESS) { + pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; + pnetwork->BcnInfo.group_cipher = group_cipher; + pnetwork->BcnInfo.is_8021x = is8021x; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s: pnetwork->pairwise_cipher: %d, is_" + "8021x is %d", __func__, + pnetwork->BcnInfo.pairwise_cipher, + pnetwork->BcnInfo.is_8021x)); + ret = _SUCCESS; + } + } else { + pbuf = rtw_get_wpa2_ie23a(&pnetwork->network.IEs[12], &wpa_ielen, + pnetwork->network.IELength - 12); + + if (pbuf && (wpa_ielen > 0)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("get RSN IE\n")); + r = rtw_parse_wpa2_ie23a(pbuf, wpa_ielen + 2, + &group_cipher, &pairwise_cipher, + &is8021x); + if (r == _SUCCESS) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("get RSN IE OK!!!\n")); + pnetwork->BcnInfo.pairwise_cipher = + pairwise_cipher; + pnetwork->BcnInfo.group_cipher = group_cipher; + pnetwork->BcnInfo.is_8021x = is8021x; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s: pnetwork->pairwise_cipher: %d," + "pnetwork->group_cipher is %d, " + "is_8021x is %d", __func__, + pnetwork->BcnInfo.pairwise_cipher, + pnetwork->BcnInfo.group_cipher, + pnetwork->BcnInfo.is_8021x)); + ret = _SUCCESS; + } + } + } + + return ret; +} + +void rtw_get_bcn_info23a(struct wlan_network *pnetwork) +{ + unsigned short cap = 0; + u8 bencrypt = 0; + /* u8 wpa_ie[255], rsn_ie[255]; */ + u16 wpa_len = 0, rsn_len = 0; + struct HT_info_element *pht_info = NULL; + struct ieee80211_ht_cap *pht_cap = NULL; + unsigned int len; + unsigned char *p; + + memcpy(&cap, rtw_get_capability23a_from_ie(pnetwork->network.IEs), 2); + cap = le16_to_cpu(cap); + if (cap & WLAN_CAPABILITY_PRIVACY) { + bencrypt = 1; + pnetwork->network.Privacy = 1; + } else { + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; + } + rtw_get_sec_ie23a(pnetwork->network.IEs, pnetwork->network.IELength, + NULL, &rsn_len, NULL, &wpa_len); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: ssid =%s\n", pnetwork->network.Ssid.ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: wpa_len =%d rsn_len =%d\n", + wpa_len, rsn_len)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: ssid =%s\n", pnetwork->network.Ssid.ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: wpa_len =%d rsn_len =%d\n", + wpa_len, rsn_len)); + + if (rsn_len > 0) { + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; + } else if (wpa_len > 0) { + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; + } else { + if (bencrypt) + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; + } + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: pnetwork->encryp_protocol is %x\n", + pnetwork->BcnInfo.encryp_protocol)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("rtw_get_bcn_info23a: pnetwork->encryp_protocol is %x\n", + pnetwork->BcnInfo.encryp_protocol)); + rtw_get_cipher_info(pnetwork); + + /* get bwmode and ch_offset */ + /* parsing HT_CAP_IE */ + p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_, + _HT_CAPABILITY_IE_, &len, + pnetwork->network.IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_cap = (struct ieee80211_ht_cap *)(p + 2); + pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info; + } else { + pnetwork->BcnInfo.ht_cap_info = 0; + } + /* parsing HT_INFO_IE */ + p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_, + _HT_ADD_INFO_IE_, &len, + pnetwork->network.IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_info = (struct HT_info_element *)(p + 2); + pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; + } else { + pnetwork->BcnInfo.ht_info_infos_0 = 0; + } +} + +/* show MCS rate, unit: 100Kbps */ +u16 rtw_mcs_rate23a(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, + unsigned char * MCS_rate) +{ + u16 max_rate = 0; + + if (rf_type == RF_1T1R) { + if (MCS_rate[0] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350): + ((short_GI_20)?722:650); + else if (MCS_rate[0] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215): + ((short_GI_20)?650:585); + else if (MCS_rate[0] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080): + ((short_GI_20)?578:520); + else if (MCS_rate[0] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI_40)?900:810): + ((short_GI_20)?433:390); + else if (MCS_rate[0] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI_40)?600:540): + ((short_GI_20)?289:260); + else if (MCS_rate[0] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI_40)?450:405): + ((short_GI_20)?217:195); + else if (MCS_rate[0] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI_40)?300:270): + ((short_GI_20)?144:130); + else if (MCS_rate[0] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI_40)?150:135): + ((short_GI_20)?72:65); + } else { + if (MCS_rate[1]) { + if (MCS_rate[1] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI_40)?3000:2700):((short_GI_20)?1444:1300); + else if (MCS_rate[1] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI_40)?2700:2430):((short_GI_20)?1300:1170); + else if (MCS_rate[1] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI_40)?2400:2160):((short_GI_20)?1156:1040); + else if (MCS_rate[1] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1800:1620):((short_GI_20)?867:780); + else if (MCS_rate[1] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520); + else if (MCS_rate[1] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390); + else if (MCS_rate[1] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260); + else if (MCS_rate[1] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130); + } else { + if (MCS_rate[0] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350):((short_GI_20)?722:650); + else if (MCS_rate[0] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215):((short_GI_20)?650:585); + else if (MCS_rate[0] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520); + else if (MCS_rate[0] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390); + else if (MCS_rate[0] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260); + else if (MCS_rate[0] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI_40)?450:405):((short_GI_20)?217:195); + else if (MCS_rate[0] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130); + else if (MCS_rate[0] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI_40)?150:135):((short_GI_20)?72:65); + } + } + return max_rate; +} + +int rtw_action_frame_parse23a(const u8 *frame, u32 frame_len, u8* category, + u8 *action) +{ + const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); + u16 fc; + u8 c, a = 0; + + fc = le16_to_cpu(((struct ieee80211_hdr_3addr *)frame)->frame_control); + + if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) != + (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION)) { + return false; + } + + c = frame_body[0]; + + switch (c) { + case WLAN_CATEGORY_VENDOR_SPECIFIC: /* vendor-specific */ + break; + default: + a = frame_body[1]; + } + + if (category) + *category = c; + if (action) + *action = a; + + return true; +} + +static const char *_action_public_str23a[] = { + "ACT_PUB_BSSCOEXIST", + "ACT_PUB_DSE_ENABLE", + "ACT_PUB_DSE_DEENABLE", + "ACT_PUB_DSE_REG_LOCATION", + "ACT_PUB_EXT_CHL_SWITCH", + "ACT_PUB_DSE_MSR_REQ", + "ACT_PUB_DSE_MSR_RPRT", + "ACT_PUB_MP", + "ACT_PUB_DSE_PWR_CONSTRAINT", + "ACT_PUB_VENDOR", + "ACT_PUB_GAS_INITIAL_REQ", + "ACT_PUB_GAS_INITIAL_RSP", + "ACT_PUB_GAS_COMEBACK_REQ", + "ACT_PUB_GAS_COMEBACK_RSP", + "ACT_PUB_TDLS_DISCOVERY_RSP", + "ACT_PUB_LOCATION_TRACK", + "ACT_PUB_RSVD", +}; + +const char *action_public_str23a(u8 action) +{ + action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; + return _action_public_str23a[action]; +} diff --git a/drivers/staging/rtl8723au/core/rtw_io.c b/drivers/staging/rtl8723au/core/rtw_io.c new file mode 100644 index 000000000000..1cae8d7659b9 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_io.c @@ -0,0 +1,266 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/* + +The purpose of rtw_io.c + +a. provides the API + +b. provides the protocol engine + +c. provides the software interface between caller and the hardware interface + +Compiler Flag Option: + +1. For USB: + a. USE_ASYNC_IRP: Both sync/async operations are provided. + +Only sync read/rtw_write_mem operations are provided. + +jackson@realtek.com.tw + +*/ + +#define _RTW_IO_C_ +#include +#include +#include +#include + +#include + +u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr) +{ + u8 r_val; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + r_val = pintfhdl->io_ops._read8(pintfhdl, addr); + + return r_val; +} + +u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr) +{ + u16 r_val; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + r_val = pintfhdl->io_ops._read16(pintfhdl, addr); + + return le16_to_cpu(r_val); +} + +u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr) +{ + u32 r_val; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + r_val = pintfhdl->io_ops._read32(pintfhdl, addr); + + return le32_to_cpu(r_val); +} + +int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + ret = pintfhdl->io_ops._write8(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} + +int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + val = cpu_to_le16(val); + ret = pintfhdl->io_ops._write16(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} +int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + val = cpu_to_le32(val); + ret = pintfhdl->io_ops._write32(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} + +int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr , u32 length , u8 *pdata) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = (struct intf_hdl*)&pio_priv->intf; + int ret; + + ret = pintfhdl->io_ops._writeN(pintfhdl, addr, length, pdata); + + return RTW_STATUS_CODE23a(ret); +} +int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + ret = pintfhdl->io_ops._write8_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} +int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + val = cpu_to_le16(val); + ret = pintfhdl->io_ops._write16_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} +int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + int ret; + + val = cpu_to_le32(val); + ret = pintfhdl->io_ops._write32_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE23a(ret); +} + +void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + if ((adapter->bDriverStopped == true) || + (adapter->bSurpriseRemoved == true)) { + RT_TRACE(_module_rtl871x_io_c_, _drv_info_, + ("rtw_read_mem:bDriverStopped(%d) OR " + "bSurpriseRemoved(%d)", adapter->bDriverStopped, + adapter->bSurpriseRemoved)); + return; + } + + pintfhdl->io_ops._read_mem(pintfhdl, addr, cnt, pmem); +} + +void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + pintfhdl->io_ops._write_mem(pintfhdl, addr, cnt, pmem); +} + +void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, + struct recv_buf *rbuf) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + if ((adapter->bDriverStopped == true) || + (adapter->bSurpriseRemoved == true)) { + RT_TRACE(_module_rtl871x_io_c_, _drv_info_, + ("rtw_read_port:bDriverStopped(%d) OR " + "bSurpriseRemoved(%d)", adapter->bDriverStopped, + adapter->bSurpriseRemoved)); + return; + } + + pintfhdl->io_ops._read_port(pintfhdl, addr, cnt, rbuf); +} + +void _rtw_read_port23a_cancel(struct rtw_adapter *adapter) +{ + void (*_read_port_cancel)(struct intf_hdl *pintfhdl); + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + _read_port_cancel = pintfhdl->io_ops._read_port_cancel; + + if (_read_port_cancel) + _read_port_cancel(pintfhdl); +} + +u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, + struct xmit_buf *xbuf) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + u32 ret = _SUCCESS; + + ret = pintfhdl->io_ops._write_port(pintfhdl, addr, cnt, xbuf); + + return ret; +} + +u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, + struct xmit_buf *pxmitbuf, int timeout_ms) +{ + int ret = _SUCCESS; + struct submit_ctx sctx; + + rtw_sctx_init23a(&sctx, timeout_ms); + pxmitbuf->sctx = &sctx; + + ret = _rtw_write_port23a(adapter, addr, cnt, pxmitbuf); + + if (ret == _SUCCESS) + ret = rtw_sctx_wait23a(&sctx); + + return ret; +} + +void _rtw_write_port23a_cancel(struct rtw_adapter *adapter) +{ + void (*_write_port_cancel)(struct intf_hdl *pintfhdl); + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &pio_priv->intf; + + _write_port_cancel = pintfhdl->io_ops._write_port_cancel; + + if (_write_port_cancel) + _write_port_cancel(pintfhdl); +} + +int rtw_init_io_priv23a(struct rtw_adapter *padapter, + void (*set_intf_ops)(struct _io_ops *pops)) +{ + struct io_priv *piopriv = &padapter->iopriv; + struct intf_hdl *pintf = &piopriv->intf; + + if (set_intf_ops == NULL) + return _FAIL; + + piopriv->padapter = padapter; + pintf->padapter = padapter; + pintf->pintf_dev = adapter_to_dvobj(padapter); + + set_intf_ops(&pintf->io_ops); + + return _SUCCESS; +} diff --git a/drivers/staging/rtl8723au/core/rtw_ioctl_set.c b/drivers/staging/rtl8723au/core/rtw_ioctl_set.c new file mode 100644 index 000000000000..30d7185e5637 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_ioctl_set.c @@ -0,0 +1,601 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_IOCTL_SET_C_ + +#include +#include +#include +#include + +#include +#include +#include + +u8 rtw_do_join23a(struct rtw_adapter *padapter) +{ + struct list_head *plist, *phead; + u8* pibss = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + u8 ret = _SUCCESS; + + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + phead = get_list_head(queue); + plist = phead->next; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("\n rtw_do_join23a: phead = %p; plist = %p\n\n\n", + phead, plist)); + + pmlmepriv->cur_network.join_res = -2; + + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + pmlmepriv->to_join = true; + + if (_rtw_queue_empty23a(queue) == true) { + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + /* when set_ssid/set_bssid for rtw_do_join23a(), but + scanning queue is empty */ + /* we try to issue sitesurvey firstly */ + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false || + rtw_to_roaming(padapter) > 0) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("rtw_do_join23a(): site survey if scanned_queue " + "is empty\n.")); + /* submit site_survey23a_cmd */ + ret = rtw_sitesurvey_cmd23a(padapter, + &pmlmepriv->assoc_ssid, 1, + NULL, 0); + if (ret != _SUCCESS) { + pmlmepriv->to_join = false; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("rtw_do_join23a(): site survey return " + "error\n.")); + } + } else { + pmlmepriv->to_join = false; + ret = _FAIL; + } + + goto exit; + } else { + int select_ret; + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + select_ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv); + if (select_ret == _SUCCESS) { + pmlmepriv->to_join = false; + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + } else { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { + struct wlan_bssid_ex *pdev_network; + /* submit createbss_cmd to change to a + ADHOC_MASTER */ + + /* pmlmepriv->lock has been acquired by + caller... */ + pdev_network = + &padapter->registrypriv.dev_network; + + pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; + + pibss = padapter->registrypriv.dev_network.MacAddress; + + memcpy(&pdev_network->Ssid, + &pmlmepriv->assoc_ssid, + sizeof(struct cfg80211_ssid)); + + rtw_update_registrypriv_dev_network23a(padapter); + + rtw_generate_random_ibss23a(pibss); + + if (rtw_createbss_cmd23a(padapter) != _SUCCESS) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, + _drv_err_, + ("***Error =>do_goin: rtw_creat" + "ebss_cmd status FAIL***\n")); + ret = false; + goto exit; + } + + pmlmepriv->to_join = false; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, + _drv_info_, + ("***Error => rtw_select_and_join_from" + "_scanned_queue FAIL under STA_Mode" + "***\n ")); + } else { + /* can't associate ; reset under-linking */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + /* when set_ssid/set_bssid for rtw_do_join23a(), + but there are no desired bss in scanning + queue */ + /* we try to issue sitesurvey firstly */ + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == + false || rtw_to_roaming(padapter) > 0) { + /* DBG_8723A("rtw_do_join23a() when no " + "desired bss in scanning queue\n"); + */ + ret = rtw_sitesurvey_cmd23a(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); + if (ret != _SUCCESS) { + pmlmepriv->to_join = false; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n.")); + } + } else { + ret = _FAIL; + pmlmepriv->to_join = false; + } + } + } + } + +exit: + + return ret; +} + +u8 rtw_set_802_11_ssid23a(struct rtw_adapter* padapter, struct cfg80211_ssid *ssid) +{ + u8 status = _SUCCESS; + u32 cur_time = 0; + + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork = &pmlmepriv->cur_network; + + + + DBG_8723A_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n", + ssid->ssid, get_fwstate(pmlmepriv)); + + if (padapter->hw_init_completed == false) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("set_ssid: hw_init_completed == false =>exit!!!\n")); + status = _FAIL; + goto exit; + } + + spin_lock_bh(&pmlmepriv->lock); + + DBG_8723A("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { + goto handle_tkip_countermeasure; + } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { + goto release_mlme_lock; + } + + if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) + { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); + + if ((pmlmepriv->assoc_ssid.ssid_len == ssid->ssid_len) && + !memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid, + ssid->ssid_len)) { + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) + { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("Set SSID is the same ssid, fw_state = 0x%08x\n", + get_fwstate(pmlmepriv))); + + if (rtw_is_same_ibss23a(padapter, pnetwork) == false) + { + /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ + rtw_disassoc_cmd23a(padapter, 0, true); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + rtw_indicate_disconnect23a(padapter); + + rtw_free_assoc_resources23a(padapter, 1); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } else { + goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ + } + } else { + rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_JOINBSS, 1); + } + } else { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("Set SSID not the same ssid\n")); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("set_ssid =[%s] len = 0x%x\n", ssid->ssid, + (unsigned int)ssid->ssid_len)); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("assoc_ssid =[%s] len = 0x%x\n", + pmlmepriv->assoc_ssid.ssid, + (unsigned int)pmlmepriv->assoc_ssid.ssid_len)); + + rtw_disassoc_cmd23a(padapter, 0, true); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + rtw_indicate_disconnect23a(padapter); + + rtw_free_assoc_resources23a(padapter, 1); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + +handle_tkip_countermeasure: + + if (padapter->securitypriv.btkip_countermeasure == true) { + cur_time = jiffies; + + if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) + { + padapter->securitypriv.btkip_countermeasure = false; + padapter->securitypriv.btkip_countermeasure_time = 0; + } + else + { + status = _FAIL; + goto release_mlme_lock; + } + } + + memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct cfg80211_ssid)); + pmlmepriv->assoc_by_bssid = false; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { + pmlmepriv->to_join = true; + } + else { + status = rtw_do_join23a(padapter); + } + +release_mlme_lock: + spin_unlock_bh(&pmlmepriv->lock); + +exit: + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("-rtw_set_802_11_ssid23a: status =%d\n", status)); + + + + return status; +} + +u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter, + enum ndis_802_11_net_infra networktype) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + enum ndis_802_11_net_infra* pold_state = &cur_network->network.InfrastructureMode; + + + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_, + ("+rtw_set_802_11_infrastructure_mode23a: old =%d new =%d fw_state = 0x%08x\n", + *pold_state, networktype, get_fwstate(pmlmepriv))); + + if (*pold_state != networktype) + { + spin_lock_bh(&pmlmepriv->lock); + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!")); + /* DBG_8723A("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ + + if (*pold_state == Ndis802_11APMode) + { + /* change to other mode from Ndis802_11APMode */ + cur_network->join_res = -1; + +#ifdef CONFIG_8723AU_AP_MODE + stop_ap_mode23a(padapter); +#endif + } + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||(*pold_state == Ndis802_11IBSS)) + rtw_disassoc_cmd23a(padapter, 0, true); + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) + rtw_free_assoc_resources23a(padapter, 1); + + if ((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS)) + { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + rtw_indicate_disconnect23a(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ + } + } + + *pold_state = networktype; + + _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); + + switch (networktype) + { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + + case Ndis802_11APMode: + set_fwstate(pmlmepriv, WIFI_AP_STATE); +#ifdef CONFIG_8723AU_AP_MODE + start_ap_mode23a(padapter); + /* rtw_indicate_connect23a(padapter); */ +#endif + + break; + + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + } + + /* SecClearAllKeys(adapter); */ + + /* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */ + /* get_fwstate(pmlmepriv))); */ + + spin_unlock_bh(&pmlmepriv->lock); + } + + + + return true; +} + +u8 rtw_set_802_11_bssid23a_list_scan(struct rtw_adapter *padapter, + struct cfg80211_ssid *pssid, int ssid_max_num) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 res = true; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("+rtw_set_802_11_bssid23a_list_scan(), fw_state =%x\n", + get_fwstate(pmlmepriv))); + + if (!padapter) { + res = false; + goto exit; + } + if (padapter->hw_init_completed == false) { + res = false; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("\n === rtw_set_802_11_bssid23a_list_scan:" + "hw_init_completed == false ===\n")); + goto exit; + } + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) || + (pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) { + /* Scan or linking is in progress, do nothing. */ + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("rtw_set_802_11_bssid23a_list_scan fail since fw_state " + "= %x\n", get_fwstate(pmlmepriv))); + res = true; + + if (check_fwstate(pmlmepriv, + (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n")); + } else { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("\n###pmlmepriv->sitesurveyctrl.traffic_" + "busy == true\n")); + } + } else { + if (rtw_is_scan_deny(padapter)) { + DBG_8723A(FUNC_ADPT_FMT": scan deny\n", + FUNC_ADPT_ARG(padapter)); + return _SUCCESS; + } + + spin_lock_bh(&pmlmepriv->lock); + + res = rtw_sitesurvey_cmd23a(padapter, pssid, ssid_max_num, + NULL, 0); + + spin_unlock_bh(&pmlmepriv->lock); + } +exit: + return res; +} + +u8 rtw_set_802_11_authentication_mode23a(struct rtw_adapter* padapter, + enum ndis_802_11_auth_mode authmode) +{ + struct security_priv *psecuritypriv = &padapter->securitypriv; + int res; + u8 ret; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("set_802_11_auth.mode(): mode =%x\n", authmode)); + + psecuritypriv->ndisauthtype = authmode; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("rtw_set_802_11_authentication_mode23a:" + "psecuritypriv->ndisauthtype =%d", + psecuritypriv->ndisauthtype)); + + if (psecuritypriv->ndisauthtype > 3) + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + + res = rtw_set_auth23a(padapter, psecuritypriv); + + if (res == _SUCCESS) + ret = true; + else + ret = false; + + return ret; +} + +u8 rtw_set_802_11_add_wep23a(struct rtw_adapter* padapter, + struct ndis_802_11_wep *wep) +{ + u8 bdefaultkey; + u8 btransmitkey; + int keyid, res; + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 ret = _SUCCESS; + + bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? false : true; + btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? true : false; + keyid = wep->KeyIndex & 0x3fffffff; + + if (keyid >= 4) { + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, + ("MgntActrtw_set_802_11_add_wep23a:keyid>4 =>fail\n")); + ret = false; + goto exit; + } + + switch (wep->KeyLength) + { + case 5: + psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 5\n")); + break; + case 13: + psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 13\n")); + break; + default: + psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength!= 5 " + "or 13\n")); + break; + } + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("rtw_set_802_11_add_wep23a:befor memcpy, wep->KeyLength = 0x%x " + "wep->KeyIndex = 0x%x keyid =%x\n", + wep->KeyLength, wep->KeyIndex, keyid)); + + memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0], + &wep->KeyMaterial, wep->KeyLength); + + psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength; + + psecuritypriv->dot11PrivacyKeyIndex = keyid; + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, + ("rtw_set_802_11_add_wep23a:security key material : %x %x %x %x " + "%x %x %x %x %x %x %x %x %x\n", + psecuritypriv->dot11DefKey[keyid].skey[0], + psecuritypriv->dot11DefKey[keyid].skey[1], + psecuritypriv->dot11DefKey[keyid].skey[2], + psecuritypriv->dot11DefKey[keyid].skey[3], + psecuritypriv->dot11DefKey[keyid].skey[4], + psecuritypriv->dot11DefKey[keyid].skey[5], + psecuritypriv->dot11DefKey[keyid].skey[6], + psecuritypriv->dot11DefKey[keyid].skey[7], + psecuritypriv->dot11DefKey[keyid].skey[8], + psecuritypriv->dot11DefKey[keyid].skey[9], + psecuritypriv->dot11DefKey[keyid].skey[10], + psecuritypriv->dot11DefKey[keyid].skey[11], + psecuritypriv->dot11DefKey[keyid].skey[12])); + + res = rtw_set_key23a(padapter, psecuritypriv, keyid, 1); + + if (res == _FAIL) + ret = false; +exit: + + return ret; +} + +/* +* rtw_get_cur_max_rate23a - +* @adapter: pointer to _adapter structure +* +* Return 0 or 100Kbps +*/ +u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter) +{ + int i = 0; + u8 *p; + u16 rate = 0, max_rate = 0; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct registry_priv *pregistrypriv = &adapter->registrypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct ieee80211_ht_cap *pht_capie; + u8 rf_type = 0; + u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0; + u16 mcs_rate = 0; + u32 ht_ielen = 0; + + if (!check_fwstate(pmlmepriv, _FW_LINKED) && + !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) + return 0; + + if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) { + p = rtw_get_ie23a(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, + &ht_ielen, pcur_bss->IELength - 12); + if (p && ht_ielen > 0) { + pht_capie = (struct ieee80211_ht_cap *)(p + 2); + + memcpy(&mcs_rate, &pht_capie->mcs, 2); + + /* bw_40MHz = (pht_capie->cap_info& + IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1:0; */ + /* cur_bwmod is updated by beacon, pmlmeinfo is + updated by association response */ + bw_40MHz = (pmlmeext->cur_bwmode && + (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & + pmlmeinfo->HT_info.infos[0])) ? 1:0; + + /* short_GI = (pht_capie->cap_info & (IEEE80211_HT_CAP + _SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; */ + short_GI_20 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_20) ? 1:0; + short_GI_40 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_40) ? 1:0; + + rtw23a_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, + (u8 *)(&rf_type)); + max_rate = rtw_mcs_rate23a(rf_type, bw_40MHz & + pregistrypriv->cbw40_enable, + short_GI_20, short_GI_40, + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate + ); + } + } else { + while ((pcur_bss->SupportedRates[i] != 0) && + (pcur_bss->SupportedRates[i] != 0xFF)) { + rate = pcur_bss->SupportedRates[i] & 0x7F; + if (rate>max_rate) + max_rate = rate; + i++; + } + + max_rate = max_rate * 10 / 2; + } + + return max_rate; +} diff --git a/drivers/staging/rtl8723au/core/rtw_led.c b/drivers/staging/rtl8723au/core/rtw_led.c new file mode 100644 index 000000000000..68532a3b2c14 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_led.c @@ -0,0 +1,1899 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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 +#include + +/* */ +/* Description: */ +/* Callback function of LED BlinkTimer, */ +/* it just schedules to corresponding BlinkWorkItem/led_blink_hdl23a */ +/* */ +static void BlinkTimerCallback(unsigned long data) +{ + struct led_8723a *pLed = (struct led_8723a *)data; + struct rtw_adapter *padapter = pLed->padapter; + + /* DBG_8723A("%s\n", __func__); */ + + if ((padapter->bSurpriseRemoved == true) || (padapter->bDriverStopped == true)) + { + /* DBG_8723A("%s bSurpriseRemoved:%d, bDriverStopped:%d\n", __func__, padapter->bSurpriseRemoved, padapter->bDriverStopped); */ + return; + } + schedule_work(&pLed->BlinkWorkItem); +} + +/* */ +/* Description: */ +/* Callback function of LED BlinkWorkItem. */ +/* We dispatch acture LED blink action according to LedStrategy. */ +/* */ +void BlinkWorkItemCallback23a(struct work_struct *work) +{ + struct led_8723a *pLed = container_of(work, struct led_8723a, BlinkWorkItem); + BlinkHandler23a(pLed); +} + +/* */ +/* Description: */ +/* Reset status of led_8723a object. */ +/* */ +void ResetLedStatus23a(struct led_8723a * pLed) { + + pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */ + pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */ + + pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */ + pLed->bLedWPSBlinkInProgress = false; + + pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */ + pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */ + + pLed->bLedNoLinkBlinkInProgress = false; + pLed->bLedLinkBlinkInProgress = false; + pLed->bLedStartToLinkBlinkInProgress = false; + pLed->bLedScanBlinkInProgress = false; +} + + /* */ +/* Description: */ +/* Initialize an led_8723a object. */ +/* */ +void +InitLed871x23a(struct rtw_adapter *padapter, struct led_8723a *pLed, enum led_pin_8723a LedPin) +{ + pLed->padapter = padapter; + pLed->LedPin = LedPin; + + ResetLedStatus23a(pLed); + + setup_timer(&pLed->BlinkTimer, BlinkTimerCallback, (unsigned long)pLed); + + INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback23a); +} + +/* */ +/* Description: */ +/* DeInitialize an led_8723a object. */ +/* */ +void +DeInitLed871x23a(struct led_8723a *pLed) +{ + cancel_work_sync(&pLed->BlinkWorkItem); + del_timer_sync(&pLed->BlinkTimer); + ResetLedStatus23a(pLed); +} + +/* Description: */ +/* Implementation of LED blinking behavior. */ +/* It toggle off LED and schedule corresponding timer if necessary. */ + +static void SwLedBlink(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + + /* Determine if we shall change LED state again. */ + pLed->BlinkTimes--; + switch (pLed->CurrLedState) { + + case LED_BLINK_NORMAL: + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + case LED_BLINK_StartToBlink: + if (check_fwstate(pmlmepriv, _FW_LINKED) && + check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + bStopBlinking = true; + if (check_fwstate(pmlmepriv, _FW_LINKED) && + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) + bStopBlinking = true; + else if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + case LED_BLINK_WPS: + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + break; + default: + bStopBlinking = true; + break; + } + + if (bStopBlinking) { + if ((check_fwstate(pmlmepriv, _FW_LINKED)) && !pLed->bLedOn) + SwLedOn23a(padapter, pLed); + else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && pLed->bLedOn) + SwLedOff23a(padapter, pLed); + + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = false; + } else { + /* Assign LED state to toggle. */ + if (pLed->BlinkingLedState == RTW_LED_ON) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + /* Schedule a timer to toggle LED state. */ + switch (pLed->CurrLedState) { + case LED_BLINK_NORMAL: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + break; + case LED_BLINK_SLOWLY: + case LED_BLINK_StartToBlink: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + break; + case LED_BLINK_WPS: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_LONG_INTERVAL)); + break; + default: + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + break; + } + } +} + +static void SwLedBlink1(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + unsigned long delay = 0; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + ResetLedStatus23a(pLed); + return; + } + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + break; + case LED_BLINK_NORMAL: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + break; + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } else if (check_fwstate(pmlmepriv, + _FW_LINKED) == false) { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = false; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + break; + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + break; + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) + bStopBlinking = false; + else + bStopBlinking = true; + if (bStopBlinking) { + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + + pLed->bLedWPSBlinkInProgress = false; + } else { + pLed->BlinkingLedState = RTW_LED_OFF; + delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA; + } + break; + default: + break; + } + if (delay) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); +} + +static void SwLedBlink2(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + switch (pLed->CurrLedState) { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("stop scan blink CurrLedState %d\n", + pLed->CurrLedState)); + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("stop scan blink CurrLedState %d\n", + pLed->CurrLedState)); + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + } + break; + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = true; + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("stop CurrLedState %d\n", pLed->CurrLedState)); + + } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, + ("stop CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->bLedBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + } + break; + default: + break; + } +} + +static void SwLedBlink3(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 bStopBlinking = false; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) + { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } + else + { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + + switch (pLed->CurrLedState) + { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + { + bStopBlinking = true; + } + + if (bStopBlinking) + { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) + { + SwLedOff23a(padapter, pLed); + } + else if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + SwLedOn23a(padapter, pLed); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + else if (check_fwstate(pmlmepriv, _FW_LINKED) == false) + { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff23a(padapter, pLed); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->bLedScanBlinkInProgress = false; + } + else + { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) + { + SwLedOff23a(padapter, pLed); + } + else + { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + { + bStopBlinking = true; + } + if (bStopBlinking) + { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) + { + SwLedOff23a(padapter, pLed); + } + else if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + + if (!pLed->bLedOn) + SwLedOn23a(padapter, pLed); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + else if (check_fwstate(pmlmepriv, _FW_LINKED) == false) + { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedOn) + SwLedOff23a(padapter, pLed); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->bLedBlinkInProgress = false; + } + else + { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) + { + SwLedOff23a(padapter, pLed); + } + else + { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) + { + pLed->BlinkingLedState = RTW_LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA)); + bStopBlinking = false; + } else { + bStopBlinking = true; + } + + if (bStopBlinking) + { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) + { + SwLedOff23a(padapter, pLed); + } + else + { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + pLed->bLedWPSBlinkInProgress = false; + } + break; + + default: + break; + } +} + +static void SwLedBlink4(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &padapter->ledpriv; + struct led_8723a *pLed1 = &ledpriv->SwLed1; + u8 bStopBlinking = false; + unsigned long delay = 0; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) + { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + + if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) + { + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + SwLedOff23a(padapter, pLed1); + } + + switch (pLed->CurrLedState) + { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + break; + + case LED_BLINK_StartToBlink: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + delay = LED_BLINK_SLOWLY_INTERVAL; + } else { + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NORMAL_INTERVAL; + } + break; + + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + bStopBlinking = false; + } + + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + pLed->bLedNoLinkBlinkInProgress = false; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + } + pLed->bLedScanBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + bStopBlinking = true; + } + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + } + pLed->bLedBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + delay = LED_BLINK_SLOWLY_INTERVAL; + } else { + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NORMAL_INTERVAL; + } + break; + + case LED_BLINK_WPS_STOP: /* WPS authentication fail */ + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + delay = LED_BLINK_NORMAL_INTERVAL; + break; + + case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + if (pLed->bLedOn) { + pLed->BlinkTimes = 1; + } else { + bStopBlinking = true; + } + } + + if (bStopBlinking) { + pLed->BlinkTimes = 10; + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + delay = LED_BLINK_NORMAL_INTERVAL; + } + break; + + default: + break; + } + if (delay) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState)); +} + +static void SwLedBlink5(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + u8 bStopBlinking = false; + unsigned long delay = 0; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + + switch (pLed->CurrLedState) + { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + bStopBlinking = true; + } + + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff23a(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + + pLed->bLedScanBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + bStopBlinking = true; + } + + if (bStopBlinking) { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff23a(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + + pLed->bLedBlinkInProgress = false; + } else { + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff23a(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + } + break; + + default: + break; + } + + if (delay) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState)); +} + +static void SwLedBlink6(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); + } else { + SwLedOff23a(padapter, pLed); + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); + } + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n")); +} + +/* ALPHA, added by chiyoko, 20090106 */ +static void +SwLedControlMode1(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct led_8723a *pLed = &ledpriv->SwLed0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + long delay = -1; + + switch (LedAction) + { + case LED_CTL_POWER_ON: + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (pLed->bLedNoLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + } + break; + + case LED_CTL_LINK: + if (pLed->bLedLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_LINK_INTERVAL_ALPHA; + } + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + } else { + pLed->bLedWPSBlinkInProgress = true; + } + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA; + } else { + pLed->BlinkingLedState = RTW_LED_ON; + delay = 0; + } + break; + + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA; + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedNoLinkBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + + SwLedOff23a(padapter, pLed); + break; + + default: + break; + + } + + if (delay != -1) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); +} + + /* Arcadyan/Sitecom , added by chiyoko, 20090216 */ +static void +SwLedControlMode2(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct led_8723a *pLed = &ledpriv->SwLed0; + long delay = -1; + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + ; + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == false) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + break; + case LED_CTL_LINK: + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + + delay = 0; + break; + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + delay = 0; + } + break; + case LED_CTL_STOP_WPS: + pLed->bLedWPSBlinkInProgress = false; + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + delay = 0; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + break; + case LED_CTL_STOP_WPS_FAIL: + pLed->bLedWPSBlinkInProgress = false; + if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { + SwLedOff23a(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + delay = 0; + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); + } + break; + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) + { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + delay = 0; + } + break; + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + delay = 0; + break; + default: + break; + + } + + if (delay != -1) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); +} + + /* COREGA, added by chiyoko, 20090316 */ +static void +SwLedControlMode3(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct led_8723a *pLed = &ledpriv->SwLed0; + long delay = -1; + + switch (LedAction) + { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + ; + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == false) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_FASTER_INTERVAL_ALPHA; + } + break; + + case LED_CTL_LINK: + if (IS_LED_WPS_BLINKING(pLed)) + return; + + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + + delay = 0; + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + delay = LED_BLINK_SCAN_INTERVAL_ALPHA; + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } else { + pLed->bLedWPSBlinkInProgress = true; + } + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA; + } else { + pLed->BlinkingLedState = RTW_LED_ON; + delay = 0; + } + + break; + + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + delay = 0; + break; + + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) + { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + delay = 0; + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + delay = 0; + break; + + default: + break; + + } + + if (delay != -1) + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay)); + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); +} + + /* Edimax-Belkin, added by chiyoko, 20090413 */ +static void +SwLedControlMode4(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct led_8723a *pLed = &ledpriv->SwLed0; + struct led_8723a *pLed1 = &ledpriv->SwLed1; + + switch (LedAction) + { + case LED_CTL_START_TO_LINK: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer_sync(&pLed1->BlinkTimer); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, jiffies); + } + + if (pLed->bLedStartToLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + + pLed->bLedStartToLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_StartToBlink; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, + jiffies + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + } + break; + + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + /* LED1 settings */ + if (LedAction == LED_CTL_LINK) { + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer_sync(&pLed1->BlinkTimer); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, jiffies); + } + } + + if (pLed->bLedNoLinkBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; + else if (pLed->bLedScanBlinkInProgress == false) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN || + IS_LED_WPS_BLINKING(pLed)) { + return; + } + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = false; + del_timer_sync(&pLed1->BlinkTimer); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + mod_timer(&pLed->BlinkTimer, jiffies); + } + + if (pLed->bLedWPSBlinkInProgress == false) { + if (pLed->bLedNoLinkBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress == true) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + pLed->bLedWPSBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + { + pLed->BlinkingLedState = RTW_LED_OFF; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + } + } + break; + + case LED_CTL_STOP_WPS: /* WPS connect success */ + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + break; + + case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + + /* LED1 settings */ + if (pLed1->bLedWPSBlinkInProgress) + del_timer_sync(&pLed1->BlinkTimer); + else + pLed1->bLedWPSBlinkInProgress = true; + + pLed1->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + + break; + + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + + pLed->bLedNoLinkBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); + + /* LED1 settings */ + if (pLed1->bLedWPSBlinkInProgress) + del_timer_sync(&pLed1->BlinkTimer); + else + pLed1->bLedWPSBlinkInProgress = true; + + pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; + pLed1->BlinkTimes = 10; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); + + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedNoLinkBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedNoLinkBlinkInProgress = false; + } + if (pLed->bLedLinkBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedLinkBlinkInProgress = false; + } + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + if (pLed->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedWPSBlinkInProgress = false; + } + if (pLed->bLedScanBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedScanBlinkInProgress = false; + } + if (pLed->bLedStartToLinkBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedStartToLinkBlinkInProgress = false; + } + + if (pLed1->bLedWPSBlinkInProgress) { + del_timer_sync(&pLed1->BlinkTimer); + pLed1->bLedWPSBlinkInProgress = false; + } + + pLed1->BlinkingLedState = LED_UNKNOWN; + SwLedOff23a(padapter, pLed); + SwLedOff23a(padapter, pLed1); + break; + + default: + break; + + } + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); +} + + /* Sercomm-Belkin, added by chiyoko, 20090415 */ +static void +SwLedControlMode5(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct led_8723a *pLed = &ledpriv->SwLed0; + + switch (LedAction) + { + case LED_CTL_POWER_ON: + case LED_CTL_NO_LINK: + case LED_CTL_LINK: /* solid blue */ + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + + mod_timer(&pLed->BlinkTimer, jiffies); + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == true)) + ; + else if (pLed->bLedScanBlinkInProgress == false) + { + if (pLed->bLedBlinkInProgress == true) + { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + pLed->bLedScanBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == false) { + if (pLed->CurrLedState == LED_BLINK_SCAN) { + return; + } + pLed->bLedBlinkInProgress = true; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed->BlinkTimer, jiffies + + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedBlinkInProgress) { + del_timer_sync(&pLed->BlinkTimer); + pLed->bLedBlinkInProgress = false; + } + + SwLedOff23a(padapter, pLed); + break; + + default: + break; + + } + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); +} + + /* WNC-Corega, added by chiyoko, 20090902 */ +static void SwLedControlMode6(struct rtw_adapter *padapter, + enum led_ctl_mode LedAction) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + struct led_8723a *pLed0 = &ledpriv->SwLed0; + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + del_timer_sync(&pLed0->BlinkTimer); + pLed0->CurrLedState = RTW_LED_ON; + pLed0->BlinkingLedState = RTW_LED_ON; + mod_timer(&pLed0->BlinkTimer, jiffies); + break; + case LED_CTL_POWER_OFF: + SwLedOff23a(padapter, pLed0); + break; + default: + break; + } + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState)); +} + +/* */ +/* Description: */ +/* Handler function of LED Blinking. */ +/* We dispatch acture LED blink action according to LedStrategy. */ +/* */ +void BlinkHandler23a(struct led_8723a *pLed) +{ + struct rtw_adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &padapter->ledpriv; + + /* DBG_8723A("%s (%s:%d)\n", __func__, current->comm, current->pid); */ + + if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) + return; + + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + SwLedBlink(pLed); + break; + case SW_LED_MODE1: + SwLedBlink1(pLed); + break; + case SW_LED_MODE2: + SwLedBlink2(pLed); + break; + case SW_LED_MODE3: + SwLedBlink3(pLed); + break; + case SW_LED_MODE4: + SwLedBlink4(pLed); + break; + case SW_LED_MODE5: + SwLedBlink5(pLed); + break; + case SW_LED_MODE6: + SwLedBlink6(pLed); + break; + default: + break; + } +} + +void +LedControl871x23a(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) { + struct led_priv *ledpriv = &padapter->ledpriv; + + if ((padapter->bSurpriseRemoved == true) || + (padapter->bDriverStopped == true) || + (padapter->hw_init_completed == false)) { + return; + } + + if (ledpriv->bRegUseLed == false) + return; + + /* if (!priv->up) */ + /* return; */ + + /* if (priv->bInHctTest) */ + /* return; */ + + if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on && + padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) && + (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || + LedAction == LED_CTL_SITE_SURVEY || + LedAction == LED_CTL_LINK || + LedAction == LED_CTL_NO_LINK || + LedAction == LED_CTL_POWER_ON)) { + return; + } + + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + break; + case SW_LED_MODE1: + SwLedControlMode1(padapter, LedAction); + break; + case SW_LED_MODE2: + SwLedControlMode2(padapter, LedAction); + break; + case SW_LED_MODE3: + SwLedControlMode3(padapter, LedAction); + break; + case SW_LED_MODE4: + SwLedControlMode4(padapter, LedAction); + break; + case SW_LED_MODE5: + SwLedControlMode5(padapter, LedAction); + break; + case SW_LED_MODE6: + SwLedControlMode6(padapter, LedAction); + break; + default: + break; + } + + RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("LedStrategy:%d, LedAction %d\n", ledpriv->LedStrategy, LedAction)); +} diff --git a/drivers/staging/rtl8723au/core/rtw_mlme.c b/drivers/staging/rtl8723au/core/rtw_mlme.c new file mode 100644 index 000000000000..71749a37a78e --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_mlme.c @@ -0,0 +1,2499 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_MLME_C_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern u8 rtw_do_join23a(struct rtw_adapter * padapter); + +static void rtw_init_mlme_timer(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + setup_timer(&pmlmepriv->assoc_timer, rtw23a_join_to_handler, + (unsigned long)padapter); + + setup_timer(&pmlmepriv->scan_to_timer, rtw_scan_timeout_handler23a, + (unsigned long)padapter); + + setup_timer(&pmlmepriv->dynamic_chk_timer, + rtw_dynamic_check_timer_handler, (unsigned long)padapter); + + setup_timer(&pmlmepriv->set_scan_deny_timer, + rtw_set_scan_deny_timer_hdl, (unsigned long)padapter); +} + +int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + int res = _SUCCESS; + + pmlmepriv->nic_hdl = padapter; + + pmlmepriv->fw_state = 0; + pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; + pmlmepriv->scan_mode=SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ + + spin_lock_init(&pmlmepriv->lock); + _rtw_init_queue23a(&pmlmepriv->scanned_queue); + + memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct cfg80211_ssid)); + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + + rtw_clear_scan_deny(padapter); + + rtw_init_mlme_timer(padapter); + return res; +} + +static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) +{ + if(*ppie) + { + kfree(*ppie); + *plen = 0; + *ppie=NULL; + } +} + +void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) +{ +#ifdef CONFIG_8723AU_AP_MODE + kfree(pmlmepriv->assoc_req); + kfree(pmlmepriv->assoc_rsp); + rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); + + rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); +#endif + +#if defined(CONFIG_8723AU_P2P) + rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len); +#endif +} + +void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv) +{ + + rtw23a_free_mlme_priv_ie_data(pmlmepriv); + +} + +struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) +{ + struct wlan_network *pnetwork; + + pnetwork = kzalloc(sizeof(struct wlan_network), GFP_ATOMIC); + if (pnetwork) { + INIT_LIST_HEAD(&pnetwork->list); + pnetwork->network_type = 0; + pnetwork->fixed = false; + pnetwork->last_scanned = jiffies; + pnetwork->aid = 0; + pnetwork->join_res = 0; + } + + return pnetwork; +} + +void _rtw_free_network23a(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork, u8 isfreeall) +{ + u32 lifetime = SCANQUEUE_LIFETIME; + + if (!pnetwork) + return; + + if (pnetwork->fixed == true) + return; + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) + lifetime = 1; + + list_del_init(&pnetwork->list); + + kfree(pnetwork); +} + +void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork) +{ + + if (pnetwork == NULL) + return; + + if (pnetwork->fixed == true) + return; + + list_del_init(&pnetwork->list); + + kfree(pnetwork); +} + +/* + return the wlan_network with the matching addr + + Shall be calle under atomic context... to avoid possible racing condition... +*/ +struct wlan_network * +_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) +{ + struct list_head *phead, *plist; + struct wlan_network *pnetwork = NULL; + + if (is_zero_ether_addr(addr)) { + pnetwork = NULL; + goto exit; + } + + /* spin_lock_bh(&scanned_queue->lock); */ + + phead = get_list_head(scanned_queue); + plist = phead->next; + + while (plist != phead) { + pnetwork = container_of(plist, struct wlan_network, list); + + if (ether_addr_equal(addr, pnetwork->network.MacAddress)) + break; + + plist = plist->next; + } + + if(plist == phead) + pnetwork = NULL; + + /* spin_unlock_bh(&scanned_queue->lock); */ + +exit: + + return pnetwork; +} + +void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall) +{ + struct list_head *phead, *plist, *ptmp; + struct wlan_network *pnetwork; + struct mlme_priv* pmlmepriv = &padapter->mlmepriv; + struct rtw_queue *scanned_queue = &pmlmepriv->scanned_queue; + + spin_lock_bh(&scanned_queue->lock); + + phead = get_list_head(scanned_queue); + + list_for_each_safe(plist, ptmp, phead) { + pnetwork = container_of(plist, struct wlan_network, list); + + _rtw_free_network23a(pmlmepriv,pnetwork, isfreeall); + } + + spin_unlock_bh(&scanned_queue->lock); + +} + +int rtw_if_up23a(struct rtw_adapter *padapter) { + + int res; + + if(padapter->bDriverStopped || padapter->bSurpriseRemoved || + (check_fwstate(&padapter->mlmepriv, _FW_LINKED)== false)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up23a:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); + res=false; + } + else + res= true; + + return res; +} + +void rtw_generate_random_ibss23a(u8* pibss) +{ + unsigned long curtime = jiffies; + + pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */ + pibss[1] = 0x11; + pibss[2] = 0x87; + pibss[3] = (u8)(curtime & 0xff) ;/* p[0]; */ + pibss[4] = (u8)((curtime>>8) & 0xff) ;/* p[1]; */ + pibss[5] = (u8)((curtime>>16) & 0xff) ;/* p[2]; */ + + return; +} + +u8 *rtw_get_capability23a_from_ie(u8 *ie) +{ + return ie + 8 + 2; +} + +u16 rtw_get_capability23a(struct wlan_bssid_ex *bss) +{ + u16 val; + + memcpy((u8 *)&val, rtw_get_capability23a_from_ie(bss->IEs), 2); + + return le16_to_cpu(val); +} + +u8 *rtw_get_timestampe_from_ie23a(u8 *ie) +{ + return ie + 0; +} + +u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie) +{ + return ie + 8; +} + +int rtw_init_mlme_priv23a (struct rtw_adapter *padapter)/* struct mlme_priv *pmlmepriv) */ +{ + int res; + + res = _rtw_init_mlme_priv23a(padapter);/* (pmlmepriv); */ + + return res; +} + +void rtw_free_mlme_priv23a (struct mlme_priv *pmlmepriv) +{ + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv23a\n")); + _rtw_free_mlme_priv23a(pmlmepriv); + +} + +void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall); +void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall)/* struct wlan_network *pnetwork, _queue *free_queue) */ +{ + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("rtw_free_network ==> ssid = %s\n\n" , + pnetwork->network.Ssid.ssid)); + _rtw_free_network23a(pmlmepriv, pnetwork, is_freeall); + +} + +void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork); +void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) +{ + + /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_network ==> ssid = %s\n\n" , pnetwork->network.Ssid.ssid)); */ + _rtw_free_network23a_nolock23a(pmlmepriv, pnetwork); + +} + +void rtw_free_network_queue23a(struct rtw_adapter* dev, u8 isfreeall) +{ + + _rtw_free_network23a_queue23a(dev, isfreeall); + +} + +/* + return the wlan_network with the matching addr + + Shall be calle under atomic context... to avoid possible racing condition... +*/ +struct wlan_network * +rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr) +{ + struct wlan_network *pnetwork; + + pnetwork = _rtw_find_network23a(scanned_queue, addr); + + return pnetwork; +} + +int rtw_is_same_ibss23a(struct rtw_adapter *adapter, struct wlan_network *pnetwork) +{ + int ret = true; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && + (pnetwork->network.Privacy == 0)) + { + ret = false; + } + else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && + (pnetwork->network.Privacy == 1)) + { + ret = false; + } + else + { + ret = true; + } + + return ret; +} + +inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b); +inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) +{ + /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("(%s,%d)(%s,%d)\n", */ + /* a->Ssid.Ssid, a->Ssid.SsidLength, b->Ssid.Ssid, b->Ssid.SsidLength)); */ + return (a->Ssid.ssid_len == b->Ssid.ssid_len) && + !memcmp(a->Ssid.ssid, b->Ssid.ssid, a->Ssid.ssid_len); +} + +int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) +{ + u16 s_cap, d_cap; + + memcpy((u8 *)&s_cap, rtw_get_capability23a_from_ie(src->IEs), 2); + memcpy((u8 *)&d_cap, rtw_get_capability23a_from_ie(dst->IEs), 2); + + s_cap = le16_to_cpu(s_cap); + d_cap = le16_to_cpu(d_cap); + + return ((src->Ssid.ssid_len == dst->Ssid.ssid_len) && + /* (src->Configuration.DSConfig == dst->Configuration.DSConfig) && */ + ether_addr_equal(src->MacAddress, dst->MacAddress) && + ((!memcmp(src->Ssid.ssid, dst->Ssid.ssid, src->Ssid.ssid_len))) && + ((s_cap & WLAN_CAPABILITY_IBSS) == + (d_cap & WLAN_CAPABILITY_IBSS)) && + ((s_cap & WLAN_CAPABILITY_ESS) == + (d_cap & WLAN_CAPABILITY_ESS))); +} + +struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue) +{ + struct list_head *plist, *phead; + + struct wlan_network *pwlan; + struct wlan_network *oldest = NULL; + + phead = get_list_head(scanned_queue); + + list_for_each(plist, phead) { + pwlan = container_of(plist, struct wlan_network, list); + + if (pwlan->fixed != true) { + if (!oldest || time_after(oldest->last_scanned, + pwlan->last_scanned)) + oldest = pwlan; + } + } + + return oldest; +} + +void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, + struct rtw_adapter * padapter, bool update_ie) +{ + u8 ss_ori = dst->PhyInfo.SignalStrength; + u8 sq_ori = dst->PhyInfo.SignalQuality; + long rssi_ori = dst->Rssi; + + u8 ss_smp = src->PhyInfo.SignalStrength; + u8 sq_smp = src->PhyInfo.SignalQuality; + long rssi_smp = src->Rssi; + + u8 ss_final; + u8 sq_final; + long rssi_final; + + DBG_8723A("%s %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n", + __func__, src->Ssid.ssid, src->MacAddress, + src->Configuration.DSConfig, ss_ori, sq_ori, rssi_ori, + ss_smp, sq_smp, rssi_smp + ); + + /* The rule below is 1/5 for sample value, 4/5 for history value */ + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network23a(&padapter->mlmepriv.cur_network.network, src)) { + /* Take the recvpriv's value for the connected AP*/ + ss_final = padapter->recvpriv.signal_strength; + sq_final = padapter->recvpriv.signal_qual; + /* the rssi value here is undecorated, and will be used for antenna diversity */ + if (sq_smp != 101) /* from the right channel */ + rssi_final = (src->Rssi+dst->Rssi*4)/5; + else + rssi_final = rssi_ori; + } + else { + if (sq_smp != 101) { /* from the right channel */ + ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; + sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; + rssi_final = (src->Rssi+dst->Rssi*4)/5; + } else { + /* bss info not receving from the right channel, use the original RX signal infos */ + ss_final = dst->PhyInfo.SignalStrength; + sq_final = dst->PhyInfo.SignalQuality; + rssi_final = dst->Rssi; + } + + } + + if (update_ie) + memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src)); + + dst->PhyInfo.SignalStrength = ss_final; + dst->PhyInfo.SignalQuality = sq_final; + dst->Rssi = rssi_final; + + DBG_8723A("%s %s(%pM), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n", + __func__, dst->Ssid.ssid, dst->MacAddress, + dst->PhyInfo.SignalStrength, + dst->PhyInfo.SignalQuality, dst->Rssi); + +} + +static void update_current_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + if ((check_fwstate(pmlmepriv, _FW_LINKED)== true) && (is_same_network23a(&pmlmepriv->cur_network.network, pnetwork))) + { + /* RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"Same Network\n"); */ + + /* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */ + { + update_network23a(&pmlmepriv->cur_network.network, pnetwork,adapter, true); + rtw_update_protection23a(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof (struct ndis_802_11_fixed_ies), + pmlmepriv->cur_network.network.IELength); + } + } + +} + +/* + +Caller must hold pmlmepriv->lock first. + +*/ +void rtw_update_scanned_network23a(struct rtw_adapter *adapter, struct wlan_bssid_ex *target) +{ + struct list_head *plist, *phead; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_network *pnetwork = NULL; + struct wlan_network *oldest = NULL; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + u32 bssid_ex_sz; + int found = 0; + + spin_lock_bh(&queue->lock); + phead = get_list_head(queue); + + list_for_each(plist, phead) { + pnetwork = container_of(plist, struct wlan_network, list); + + if (is_same_network23a(&pnetwork->network, target)) { + found = 1; + break; + } + if (!oldest || time_after(oldest->last_scanned, + pnetwork->last_scanned)) + oldest = pnetwork; + } + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + if (!found) { + pnetwork = rtw_alloc_network(pmlmepriv); + if (!pnetwork) { + if (!oldest) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("\n\n\nsomething wrong here\n\n\n")); + goto exit; + } + pnetwork = oldest; + } else + list_add_tail(&pnetwork->list, &queue->queue); + + bssid_ex_sz = get_wlan_bssid_ex_sz(target); + target->Length = bssid_ex_sz; + memcpy(&pnetwork->network, target, bssid_ex_sz); + + /* variable initialize */ + pnetwork->fixed = false; + pnetwork->last_scanned = jiffies; + + pnetwork->network_type = 0; + pnetwork->aid = 0; + pnetwork->join_res = 0; + + /* bss info not receving from the right channel */ + if (pnetwork->network.PhyInfo.SignalQuality == 101) + pnetwork->network.PhyInfo.SignalQuality = 0; + } else { + /* + * we have an entry and we are going to update it. But + * this entry may be already expired. In this case we + * do the same as we found a new net and call the + * new_net handler + */ + bool update_ie = true; + + pnetwork->last_scanned = jiffies; + + /* target.reserved == 1, means that scanned network is + * a bcn frame. */ + if ((pnetwork->network.IELength>target->IELength) && + (target->reserved == 1)) + update_ie = false; + + update_network23a(&pnetwork->network, target,adapter, update_ie); + } + +exit: + spin_unlock_bh(&queue->lock); + +} + +void rtw_add_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork) +{ + update_current_network(adapter, pnetwork); + rtw_update_scanned_network23a(adapter, pnetwork); +} + +/* select the desired network based on the capability of the (i)bss. */ +/* check items: (1) security */ +/* (2) network_type */ +/* (3) WMM */ +/* (4) HT */ +/* (5) others */ +int rtw_is_desired_network(struct rtw_adapter *adapter, struct wlan_network *pnetwork) +{ + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u32 desired_encmode; + u32 privacy; + + /* u8 wps_ie[512]; */ + uint wps_ielen; + + int bselected = true; + + desired_encmode = psecuritypriv->ndisencryptstatus; + privacy = pnetwork->network.Privacy; + + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) + { + if (rtw_get_wps_ie23a(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)!= NULL) + { + return true; + } + else + { + return false; + } + } + if (adapter->registrypriv.wifi_spec == 1) /* for correct flow of 8021X to do.... */ + { + if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) + bselected = false; + } + + if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { + DBG_8723A("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); + bselected = false; + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) + { + if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) + bselected = false; + } + + return bselected; +} + +/* TODO: Perry : For Power Management */ +void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf) +{ + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("receive atimdone_evet\n")); + + return; +} + +void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf) +{ + u32 len; + struct wlan_bssid_ex *pnetwork; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + pnetwork = (struct wlan_bssid_ex *)pbuf; + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_survey_event_cb23a, ssid=%s\n", pnetwork->Ssid.ssid)); + + len = get_wlan_bssid_ex_sz(pnetwork); + if(len > (sizeof(struct wlan_bssid_ex))) + { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n ****rtw_survey_event_cb23a: return a wrong bss ***\n")); + return; + } + + spin_lock_bh(&pmlmepriv->lock); + + /* update IBSS_network 's timestamp */ + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) + { + /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"rtw_survey_event_cb23a : WIFI_ADHOC_MASTER_STATE\n\n"); */ + if (ether_addr_equal(pmlmepriv->cur_network.network.MacAddress, + pnetwork->MacAddress)) { + struct wlan_network* ibss_wlan = NULL; + + memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + ibss_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->MacAddress); + if (ibss_wlan) + { + memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + goto exit; + } + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + } + } + + /* lock pmlmepriv->lock when you accessing network_q */ + if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) + { + if (pnetwork->Ssid.ssid[0] == 0) + pnetwork->Ssid.ssid_len = 0; + + rtw_add_network(adapter, pnetwork); + } + +exit: + + spin_unlock_bh(&pmlmepriv->lock); + + return; +} + +void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + + spin_lock_bh(&pmlmepriv->lock); + + if (pmlmepriv->wps_probe_req_ie) { + pmlmepriv->wps_probe_req_ie_len = 0; + kfree(pmlmepriv->wps_probe_req_ie); + pmlmepriv->wps_probe_req_ie = NULL; + } + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback23a: fw_state:%x\n\n", get_fwstate(pmlmepriv))); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { + del_timer_sync(&pmlmepriv->scan_to_timer); + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + } else { + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); + } + + rtw_set_signal_stat_timer(&adapter->recvpriv); + + if (pmlmepriv->to_join == true) { + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + if (rtw_select_and_join_from_scanned_queue23a(pmlmepriv) == _SUCCESS) { + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + } else { + struct wlan_bssid_ex *pdev_network = &adapter->registrypriv.dev_network; + u8 *pibss = adapter->registrypriv.dev_network.MacAddress; + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); + + memset(&pdev_network->Ssid, 0, sizeof(struct cfg80211_ssid)); + memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct cfg80211_ssid)); + + rtw_update_registrypriv_dev_network23a(adapter); + rtw_generate_random_ibss23a(pibss); + + pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; + + if (rtw_createbss_cmd23a(adapter)!= _SUCCESS) + { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd23a status FAIL\n")); + } + + pmlmepriv->to_join = false; + } + } + } else { + int ret; + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + pmlmepriv->to_join = false; + ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv); + if (ret == _SUCCESS) { + unsigned long e; + e = msecs_to_jiffies(MAX_JOIN_TIMEOUT); + mod_timer(&pmlmepriv->assoc_timer, jiffies + e); + } else if (ret == 2)/* there is no need to wait for join */ + { + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + rtw_indicate_connect23a(adapter); + } else { + DBG_8723A("try_to_join, but select scanning queue fail, to_roaming:%d\n", rtw_to_roaming(adapter)); + if (rtw_to_roaming(adapter) != 0) { + if (--pmlmepriv->to_roaming == 0 + || _SUCCESS != rtw_sitesurvey_cmd23a(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) + ) { + rtw_set_roaming(adapter, 0); + rtw_free_assoc_resources23a(adapter, 1); + rtw_indicate_disconnect23a(adapter); + } else { + pmlmepriv->to_join = true; + } + } + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + } + } + + spin_unlock_bh(&pmlmepriv->lock); + +#ifdef CONFIG_8723AU_P2P + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + p2p_ps_wk_cmd23a(adapter, P2P_PS_SCAN_DONE, 0); +#endif /* CONFIG_8723AU_P2P */ + + rtw_os_xmit_schedule23a(adapter); + + if(pmlmeext->sitesurvey_res.bss_cnt == 0) + rtw_hal_sreset_reset23a(adapter); + + rtw_cfg80211_surveydone_event_callback(adapter); + +} + +void rtw_dummy_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf) +{ +} + +void rtw23a_fwdbg_event_callback(struct rtw_adapter *adapter , u8 *pbuf) +{ +} + +static void free_scanqueue(struct mlme_priv *pmlmepriv) +{ + struct wlan_network *pnetwork; + struct rtw_queue *scan_queue = &pmlmepriv->scanned_queue; + struct list_head *plist, *phead, *ptemp; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n")); + spin_lock_bh(&scan_queue->lock); + + phead = get_list_head(scan_queue); + + list_for_each_safe(plist, ptemp, phead) { + list_del_init(plist); + pnetwork = container_of(plist, struct wlan_network, list); + kfree(pnetwork); + } + + spin_unlock_bh(&scan_queue->lock); + +} + +/* +*rtw_free_assoc_resources23a: the caller has to lock pmlmepriv->lock +*/ +void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_queue) +{ + struct wlan_network* pwlan = NULL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources23a\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n", + MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.ssid)); + + if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) + { + struct sta_info* psta; + + psta = rtw_get_stainfo23a(&adapter->stapriv, tgt_network->network.MacAddress); + + { + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(adapter, psta); + } + + spin_unlock_bh(&pstapriv->sta_hash_lock); + + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) + { + struct sta_info* psta; + + rtw_free_all_stainfo23a(adapter); + + psta = rtw_get_bcmc_stainfo23a(adapter); + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(adapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + + rtw_init_bcmc_stainfo23a(adapter); + } + + if(lock_scanned_queue) + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + if(pwlan) + pwlan->fixed = false; + else + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_assoc_resources23a : pwlan== NULL\n\n")); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)) + rtw_free_network_nolock(pmlmepriv, pwlan); + + if(lock_scanned_queue) + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + + pmlmepriv->key_mask = 0; + +} + +/* +*rtw_indicate_connect23a: the caller has to lock pmlmepriv->lock +*/ +void rtw_indicate_connect23a(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect23a\n")); + + pmlmepriv->to_join = false; + + if(!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { + set_fwstate(pmlmepriv, _FW_LINKED); + + rtw_led_control(padapter, LED_CTL_LINK); + + rtw_os_indicate_connect23a(padapter); + } + + rtw_set_roaming(padapter, 0); + + rtw_set_scan_deny(padapter, 3000); + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect23a: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); + +} + +/* +*rtw_indicate_disconnect23a: the caller has to lock pmlmepriv->lock +*/ +void rtw_indicate_disconnect23a(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect23a\n")); + + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS); + + /* DBG_8723A("clear wps when %s\n", __func__); */ + + if (rtw_to_roaming(padapter) > 0) + _clr_fwstate_(pmlmepriv, _FW_LINKED); + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) || + (rtw_to_roaming(padapter) <= 0)) { + rtw_os_indicate_disconnect23a(padapter); + + /* set ips_deny_time to avoid enter IPS before LPS leave */ + padapter->pwrctrlpriv.ips_deny_time = + rtw_get_current_time() + rtw_ms_to_systime23a(3000); + + _clr_fwstate_(pmlmepriv, _FW_LINKED); + + rtw_led_control(padapter, LED_CTL_NO_LINK); + + rtw_clear_scan_deny(padapter); + + } + +#ifdef CONFIG_8723AU_P2P + p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); +#endif /* CONFIG_8723AU_P2P */ + + rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_DISCONNECT, 1); + +} + +inline void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted) +{ + rtw_os_indicate_scan_done23a(padapter, aborted); +} + +void rtw_scan_abort23a(struct rtw_adapter *adapter) +{ + unsigned long start; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + + start = jiffies; + pmlmeext->scan_abort = true; + while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) && + jiffies_to_msecs(jiffies - start) <= 200) { + + if (adapter->bDriverStopped || adapter->bSurpriseRemoved) + break; + + DBG_8723A(FUNC_NDEV_FMT"fw_state = _FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + msleep(20); + } + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { + if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) + DBG_8723A(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + rtw_indicate_scan_done23a(adapter, true); + } + pmlmeext->scan_abort = false; +} + +static struct sta_info *rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, struct wlan_network *pnetwork) +{ + int i; + struct sta_info *bmc_sta, *psta = NULL; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_priv *pstapriv = &padapter->stapriv; + + psta = rtw_get_stainfo23a(pstapriv, pnetwork->network.MacAddress); + if (psta == NULL) { + psta = rtw_alloc_stainfo23a(pstapriv, pnetwork->network.MacAddress); + } + + if (psta) /* update ptarget_sta */ + { + DBG_8723A("%s\n", __func__); + + psta->aid = pnetwork->join_res; + psta->mac_id = 0; + + /* sta mode */ + rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true); + + /* security related */ + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) + { + padapter->securitypriv.binstallGrpkey = false; + padapter->securitypriv.busetkipkey = false; + padapter->securitypriv.bgrpkey_handshake = false; + + psta->ieee8021x_blocked = true; + psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; + + memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof (union Keytype)); + + memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof (union Keytype)); + memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof (union Keytype)); + + memset((u8 *)&psta->dot11txpn, 0, sizeof (union pn48)); + memset((u8 *)&psta->dot11rxpn, 0, sizeof (union pn48)); + } + + /* Commented by Albert 2012/07/21 */ + /* When doing the WPS, the wps_ie_len won't equal to 0 */ + /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ + if (padapter->securitypriv.wps_ie_len != 0) + { + psta->ieee8021x_blocked = true; + padapter->securitypriv.wps_ie_len = 0; + } + + /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ + /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ + /* todo: check if AP can send A-MPDU packets */ + for (i = 0; i < 16 ; i++) + { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &psta->recvreorder_ctrl[i]; + preorder_ctrl->enable = false; + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ + } + + bmc_sta = rtw_get_bcmc_stainfo23a(padapter); + if (bmc_sta) + { + for (i = 0; i < 16 ; i++) + { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; + preorder_ctrl->enable = false; + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ + } + } + + /* misc. */ + update_sta_info23a(padapter, psta); + + } + + return psta; +} + +/* pnetwork : returns from rtw23a_joinbss_event_cb */ +/* ptarget_wlan: found from scanned_queue */ +static void rtw_joinbss_update_network23a(struct rtw_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + + DBG_8723A("%s\n", __func__); + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n" + , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); + + /* why not use ptarget_wlan?? */ + memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); + /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ + cur_network->network.IELength = ptarget_wlan->network.IELength; + memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); + + cur_network->aid = pnetwork->join_res; + + rtw_set_signal_stat_timer(&padapter->recvpriv); + padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; + padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; + /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ + padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); + DBG_8723A("%s signal_strength:%3u, rssi:%3d, signal_qual:%3u\n", + __func__, padapter->recvpriv.signal_strength, + padapter->recvpriv.rssi, padapter->recvpriv.signal_qual); + rtw_set_signal_stat_timer(&padapter->recvpriv); + + /* update fw_state will clr _FW_UNDER_LINKING here indirectly */ + switch (pnetwork->network.InfrastructureMode) { + case Ndis802_11Infrastructure: + if (pmlmepriv->fw_state&WIFI_UNDER_WPS) + pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS; + else + pmlmepriv->fw_state = WIFI_STATION_STATE; + break; + case Ndis802_11IBSS: + pmlmepriv->fw_state = WIFI_ADHOC_STATE; + break; + default: + pmlmepriv->fw_state = WIFI_NULL_STATE; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n")); + break; + } + + rtw_update_protection23a(padapter, (cur_network->network.IEs) + sizeof (struct ndis_802_11_fixed_ies), + (cur_network->network.IELength)); + + rtw_update_ht_cap23a(padapter, cur_network->network.IEs, cur_network->network.IELength); +} + +/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */ +/* pnetwork : returns from rtw23a_joinbss_event_cb */ +/* ptarget_wlan: found from scanned_queue */ +/* if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ +/* if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */ +/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL). */ + +void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf) +{ + static u8 retry=0; + struct sta_info *ptarget_sta= NULL, *pcur_sta = NULL; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; + unsigned int the_same_macaddr = false; + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("joinbss event call back received with res=%d\n", pnetwork->join_res)); + + rtw_get_encrypt_decrypt_from_registrypriv23a(adapter); + + if (pmlmepriv->assoc_ssid.ssid_len == 0) { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("@@@@@ joinbss event call back for Any SSid\n")); + } else { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("@@@@@ rtw23a_joinbss_event_cb for SSid:%s\n", + pmlmepriv->assoc_ssid.ssid)); + } + + if (ether_addr_equal(pnetwork->network.MacAddress, + cur_network->network.MacAddress)) + the_same_macaddr = true; + else + the_same_macaddr = false; + + pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); + if(pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) + { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); + return; + } + + spin_lock_bh(&pmlmepriv->lock); + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw23a_joinbss_event_cb !! _enter_critical\n")); + + if(pnetwork->join_res > 0) + { + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + retry = 0; + if (check_fwstate(pmlmepriv,_FW_UNDER_LINKING)) + { + /* s1. find ptarget_wlan */ + if(check_fwstate(pmlmepriv, _FW_LINKED)) + { + if(the_same_macaddr == true) + { + ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + } + else + { + pcur_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + if(pcur_wlan) pcur_wlan->fixed = false; + + pcur_sta = rtw_get_stainfo23a(pstapriv, cur_network->network.MacAddress); + if(pcur_sta) { + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(adapter, pcur_sta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + } + + ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); + if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + if(ptarget_wlan) ptarget_wlan->fixed = true; + } + } + + } + else + { + ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); + if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + if(ptarget_wlan) ptarget_wlan->fixed = true; + } + } + + /* s2. update cur_network */ + if(ptarget_wlan) + { + rtw_joinbss_update_network23a(adapter, ptarget_wlan, pnetwork); + } + else + { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't find ptarget_wlan when joinbss_event callback\n")); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + goto ignore_joinbss_callback; + } + + /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ + if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) + { + ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); + if(ptarget_sta==NULL) + { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't update stainfo when joinbss_event callback\n")); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + goto ignore_joinbss_callback; + } + } + + /* s4. indicate connect */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) + { + rtw_indicate_connect23a(adapter); + } else { + /* adhoc mode will rtw_indicate_connect23a when rtw_stassoc_event_callback23a */ + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); + } + + /* s5. Cancle assoc_timer */ + del_timer_sync(&pmlmepriv->assoc_timer); + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("Cancle assoc_timer\n")); + } else { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("rtw23a_joinbss_event_cb err: fw_state:%x", + get_fwstate(pmlmepriv))); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + goto ignore_joinbss_callback; + } + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + } else if(pnetwork->join_res == -4) { + rtw_reset_securitypriv23a(adapter); + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + + /* rtw_free_assoc_resources23a(adapter, 1); */ + + if((check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", + get_fwstate(pmlmepriv))); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + + } else { + /* if join_res < 0 (join fails), then try again */ + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(1)); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + +ignore_joinbss_callback: + + spin_unlock_bh(&pmlmepriv->lock); +} + +void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, u8 *pbuf) +{ + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + + mlmeext_joinbss_event_callback23a(adapter, pnetwork->join_res); + + rtw_os_xmit_schedule23a(adapter); + +} + +/* FOR AP , AD-HOC mode */ +void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta) +{ + u16 media_status; + + if (psta == NULL) return; + + media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE:1 connect */ + rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); +} + +void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) +{ + struct sta_info *psta; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct stassoc_event *pstassoc = (struct stassoc_event*)pbuf; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct wlan_network *ptarget_wlan = NULL; + + if(rtw_access_ctrl23a(adapter, pstassoc->macaddr) == false) + return; + +#ifdef CONFIG_8723AU_AP_MODE + if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) + { + psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr); + if (psta) { + /* bss_cap_update_on_sta_join23a(adapter, psta); */ + /* sta_info_update23a(adapter, psta); */ + ap_sta_info_defer_update23a(adapter, psta); + + rtw_stassoc_hw_rpt23a(adapter,psta); + } + return; + } +#endif + /* for AD-HOC mode */ + psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr); + if (psta != NULL) { + /* the sta have been in sta_info_queue => do nothing */ + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Error: rtw_stassoc_event_callback23a: sta has been in sta_hash_queue\n")); + return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ + } + + psta = rtw_alloc_stainfo23a(&adapter->stapriv, pstassoc->macaddr); + if (psta == NULL) { + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't alloc sta_info when rtw_stassoc_event_callback23a\n")); + return; + } + + /* to do : init sta_info variable */ + psta->qos_option = 0; + psta->mac_id = (uint)pstassoc->cam_id; + /* psta->aid = (uint)pstassoc->cam_id; */ + DBG_8723A("%s\n",__func__); + /* for ad-hoc mode */ + rtw_hal_set_odm_var23a(adapter,HAL_ODM_STA_INFO,psta,true); + + rtw_stassoc_hw_rpt23a(adapter,psta); + + if(adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X) + psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; + + psta->ieee8021x_blocked = false; + + spin_lock_bh(&pmlmepriv->lock); + + if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==true ) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==true ) ) + { + if(adapter->stapriv.asoc_sta_count== 2) + { + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + if(ptarget_wlan) ptarget_wlan->fixed = true; + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + rtw_indicate_connect23a(adapter); + } + } + + spin_unlock_bh(&pmlmepriv->lock); + + mlmeext_sta_add_event_callback23a(adapter, psta); +} + +void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf) +{ + int mac_id=-1; + struct sta_info *psta; + struct wlan_network* pwlan = NULL; + struct wlan_bssid_ex *pdev_network=NULL; + u8* pibss = NULL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct stadel_event *pstadel = (struct stadel_event*)pbuf; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + + psta = rtw_get_stainfo23a(&adapter->stapriv, pstadel->macaddr); + if(psta) + mac_id = psta->mac_id; + else + mac_id = pstadel->mac_id; + + DBG_8723A("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); + + if(mac_id>=0) { + u16 media_status; + media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */ + /* for STA,AP,ADHOC mode, report disconnect stauts to FW */ + rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); + } + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) + { + return; + } + + mlmeext_sta_del_event_callback23a(adapter); + + spin_lock_bh(&pmlmepriv->lock); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + { + if (rtw_to_roaming(adapter) > 0) + pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */ + else if (rtw_to_roaming(adapter) == 0) + rtw_set_roaming(adapter, adapter->registrypriv.max_roaming_times); + if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK) + rtw_set_roaming(adapter, 0); /* don't roam */ + + rtw_free_uc_swdec_pending_queue23a(adapter); + + rtw_free_assoc_resources23a(adapter, 1); + rtw_indicate_disconnect23a(adapter); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + /* remove the network entry in scanned_queue */ + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + if (pwlan) { + pwlan->fixed = false; + rtw_free_network_nolock(pmlmepriv, pwlan); + } + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + + _rtw23a_roaming(adapter, tgt_network); + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) + { + + spin_lock_bh(&pstapriv->sta_hash_lock); + rtw_free_stainfo23a(adapter, psta); + spin_unlock_bh(&pstapriv->sta_hash_lock); + + if (adapter->stapriv.asoc_sta_count == 1) /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + { + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + /* free old ibss network */ + /* pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pstadel->macaddr); */ + pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + if (pwlan) + { + pwlan->fixed = false; + rtw_free_network_nolock(pmlmepriv, pwlan); + } + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + /* re-create ibss */ + pdev_network = &adapter->registrypriv.dev_network; + pibss = adapter->registrypriv.dev_network.MacAddress; + + memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); + + memset(&pdev_network->Ssid, 0, + sizeof(struct cfg80211_ssid)); + memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, + sizeof(struct cfg80211_ssid)); + + rtw_update_registrypriv_dev_network23a(adapter); + + rtw_generate_random_ibss23a(pibss); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) + { + set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); + } + + if (rtw_createbss_cmd23a(adapter)!= _SUCCESS) + { + + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd23a status FAIL***\n ")); + + } + + } + + } + + spin_unlock_bh(&pmlmepriv->lock); + +} + +void rtw_cpwm_event_callback23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("+rtw_cpwm_event_callback23a !!!\n")); + +} + +/* +* rtw23a_join_to_handler - Timeout/faliure handler for CMD JoinBss +* @adapter: pointer to _adapter structure +*/ +void rtw23a_join_to_handler (unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + int do_join_r; + + DBG_8723A("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv)); + + if(adapter->bDriverStopped ||adapter->bSurpriseRemoved) + return; + + spin_lock_bh(&pmlmepriv->lock); + + if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */ + while(1) { + pmlmepriv->to_roaming--; + if (rtw_to_roaming(adapter) != 0) { /* try another */ + DBG_8723A("%s try another roaming\n", __func__); + if (_SUCCESS!= (do_join_r = rtw_do_join23a(adapter))) { + DBG_8723A("%s roaming do_join return %d\n", __func__ , do_join_r); + continue; + } + break; + } else { + DBG_8723A("%s We've try roaming but fail\n", __func__); + rtw_indicate_disconnect23a(adapter); + break; + } + } + } else { + rtw_indicate_disconnect23a(adapter); + free_scanqueue(pmlmepriv);/* */ + + /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */ + rtw_cfg80211_indicate_disconnect(adapter); + } + + spin_unlock_bh(&pmlmepriv->lock); + +} + +/* +* rtw_scan_timeout_handler23a - Timeout/Faliure handler for CMD SiteSurvey +* @data: pointer to _adapter structure +*/ +void rtw_scan_timeout_handler23a(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + DBG_8723A(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); + + spin_lock_bh(&pmlmepriv->lock); + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + spin_unlock_bh(&pmlmepriv->lock); + + rtw_indicate_scan_done23a(adapter, true); +} + +static void rtw_auto_scan_handler(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + /* auto site survey per 60sec */ + if (pmlmepriv->scan_interval > 0) { + pmlmepriv->scan_interval--; + if (pmlmepriv->scan_interval == 0) { + DBG_8723A("%s\n", __func__); + rtw_set_802_11_bssid23a_list_scan(padapter, NULL, 0); + pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ + } + } +} + +void rtw_dynamic_check_timer_handler(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct registry_priv *pregistrypriv = &adapter->registrypriv; + + if (adapter->hw_init_completed == false) + goto out; + + if ((adapter->bDriverStopped == true)||(adapter->bSurpriseRemoved == true)) + goto out; + + if (adapter->net_closed == true) + goto out; + + rtw_dynamic_chk_wk_cmd23a(adapter); + + if (pregistrypriv->wifi_spec == 1) + { +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) +#endif + { + /* auto site survey */ + rtw_auto_scan_handler(adapter); + } + } +out: + mod_timer(&adapter->mlmepriv.dynamic_chk_timer, + jiffies + msecs_to_jiffies(2000)); +} + +inline bool rtw_is_scan_deny(struct rtw_adapter *adapter) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + return (atomic_read(&mlmepriv->set_scan_deny) != 0) ? true : false; +} + +void rtw_clear_scan_deny(struct rtw_adapter *adapter) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + atomic_set(&mlmepriv->set_scan_deny, 0); + if (0) + DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); +} + +void rtw_set_scan_deny_timer_hdl(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + rtw_clear_scan_deny(adapter); +} + +void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + + if (0) + DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); + atomic_set(&mlmepriv->set_scan_deny, 1); + mod_timer(&mlmepriv->set_scan_deny_timer, + jiffies + msecs_to_jiffies(ms)); + +} + +#if defined(IEEE80211_SCAN_RESULT_EXPIRE) +#define RTW_SCAN_RESULT_EXPIRE IEEE80211_SCAN_RESULT_EXPIRE/HZ*1000 -1000 /* 3000 -1000 */ +#else +#define RTW_SCAN_RESULT_EXPIRE 2000 +#endif + +/* +* Select a new join candidate from the original @param candidate and @param competitor +* @return true: candidate is updated +* @return false: candidate is not updated +*/ +static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv + , struct wlan_network **candidate, struct wlan_network *competitor) +{ + int updated = false; + struct rtw_adapter *adapter = container_of(pmlmepriv, struct rtw_adapter, mlmepriv); + + /* check bssid, if needed */ + if (pmlmepriv->assoc_by_bssid == true) { + if (!ether_addr_equal(competitor->network.MacAddress, + pmlmepriv->assoc_bssid)) + goto exit; + } + + /* check ssid, if needed */ + if (pmlmepriv->assoc_ssid.ssid && pmlmepriv->assoc_ssid.ssid_len) { + if (competitor->network.Ssid.ssid_len != + pmlmepriv->assoc_ssid.ssid_len || + memcmp(competitor->network.Ssid.ssid, + pmlmepriv->assoc_ssid.ssid, + pmlmepriv->assoc_ssid.ssid_len)) + goto exit; + } + + if (rtw_is_desired_network(adapter, competitor) == false) + goto exit; + + if (rtw_to_roaming(adapter) > 0) { + unsigned int passed; + + passed = jiffies_to_msecs(jiffies - competitor->last_scanned); + if (passed >= RTW_SCAN_RESULT_EXPIRE || + is_same_ess(&competitor->network, + &pmlmepriv->cur_network.network) == false) + goto exit; + } + + if (*candidate == NULL ||(*candidate)->network.Rssinetwork.Rssi) { + *candidate = competitor; + updated = true; + } + + if (updated) { + DBG_8723A("[by_bssid:%u][assoc_ssid:%s][to_roaming:%u] new candidate: %s("MAC_FMT") rssi:%d\n", + pmlmepriv->assoc_by_bssid, + pmlmepriv->assoc_ssid.ssid, + rtw_to_roaming(adapter), + (*candidate)->network.Ssid.ssid, + MAC_ARG((*candidate)->network.MacAddress), + (int)(*candidate)->network.Rssi); + } + +exit: + return updated; +} + +/* +Calling context: +The caller of the sub-routine will be in critical section... + +The caller must hold the following spinlock + +pmlmepriv->lock + +*/ + +int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv) +{ + int ret; + struct list_head *phead, *plist, *ptmp; + struct rtw_adapter *adapter; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + struct wlan_network *pnetwork = NULL; + struct wlan_network *candidate = NULL; + + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + phead = get_list_head(queue); + adapter = pmlmepriv->nic_hdl; + + list_for_each_safe(plist, ptmp, phead) { + pnetwork = container_of(plist, struct wlan_network, list); + if (!pnetwork) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s return _FAIL:(pnetwork == NULL)\n", + __func__)); + ret = _FAIL; + goto exit; + } + + rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); + } + + if (!candidate) { + DBG_8723A("%s: return _FAIL(candidate == NULL)\n", __func__); + ret = _FAIL; + goto exit; + } else { + DBG_8723A("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__, + candidate->network.Ssid.ssid, + MAC_ARG(candidate->network.MacAddress), + candidate->network.Configuration.DSConfig); + } + + /* check for situation of _FW_LINKED */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { + DBG_8723A("%s: _FW_LINKED while ask_for_joinbss!!!\n", + __func__); + + rtw_disassoc_cmd23a(adapter, 0, true); + rtw_indicate_disconnect23a(adapter); + rtw_free_assoc_resources23a(adapter, 0); + } + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + ret = rtw_joinbss_cmd23a(adapter, candidate); + +exit: + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + + return ret; +} + +int rtw_set_auth23a(struct rtw_adapter * adapter, + struct security_priv *psecuritypriv) +{ + struct cmd_obj* pcmd; + struct setauth_parm *psetauthparm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + int res = _SUCCESS; + + pcmd = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!pcmd) { + res = _FAIL; /* try again */ + goto exit; + } + + psetauthparm = (struct setauth_parm*) + kzalloc(sizeof(struct setauth_parm), GFP_KERNEL); + if (!psetauthparm) { + kfree(pcmd); + res = _FAIL; + goto exit; + } + + psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm; + + pcmd->cmdcode = _SetAuth_CMD_; + pcmd->parmbuf = (unsigned char *)psetauthparm; + pcmd->cmdsz = (sizeof(struct setauth_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + INIT_LIST_HEAD(&pcmd->list); + + RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_, + ("after enqueue set_auth_cmd, auth_mode=%x\n", + psecuritypriv->dot11AuthAlgrthm)); + + res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); + +exit: + + return res; +} + +int rtw_set_key23a(struct rtw_adapter *adapter, + struct security_priv *psecuritypriv, int keyid, u8 set_tx) +{ + u8 keylen; + struct cmd_obj *pcmd; + struct setkey_parm *psetkeyparm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + int res = _SUCCESS; + + pcmd = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!pcmd) { + res = _FAIL; /* try again */ + goto exit; + } + psetkeyparm = (struct setkey_parm *) + kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); + if (!psetkeyparm) { + kfree(pcmd); + res = _FAIL; + goto exit; + } + + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { + psetkeyparm->algorithm = (unsigned char) + psecuritypriv->dot118021XGrpPrivacy; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("\n rtw_set_key23a: psetkeyparm->algorithm = (unsigned " + "char)psecuritypriv->dot118021XGrpPrivacy =%d\n", + psetkeyparm->algorithm)); + } else { + psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("\n rtw_set_key23a: psetkeyparm->algorithm = (u8)" + "psecuritypriv->dot11PrivacyAlgrthm =%d\n", + psetkeyparm->algorithm)); + } + psetkeyparm->keyid = (u8)keyid;/* 0~3 */ + psetkeyparm->set_tx = set_tx; + if (is_wep_enc(psetkeyparm->algorithm)) + pmlmepriv->key_mask |= CHKBIT(psetkeyparm->keyid); + + DBG_8723A("==> rtw_set_key23a algorithm(%x), keyid(%x), key_mask(%x)\n", + psetkeyparm->algorithm, psetkeyparm->keyid, + pmlmepriv->key_mask); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("\n rtw_set_key23a: psetkeyparm->algorithm =%d psetkeyparm->" + "keyid = (u8)keyid =%d\n", psetkeyparm->algorithm, keyid)); + + switch (psetkeyparm->algorithm) { + case _WEP40_: + keylen = 5; + memcpy(&psetkeyparm->key[0], + &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); + break; + case _WEP104_: + keylen = 13; + memcpy(&psetkeyparm->key[0], + &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); + break; + case _TKIP_: + keylen = 16; + memcpy(&psetkeyparm->key, + &psecuritypriv->dot118021XGrpKey[keyid], keylen); + psetkeyparm->grpkey = 1; + break; + case _AES_: + keylen = 16; + memcpy(&psetkeyparm->key, + &psecuritypriv->dot118021XGrpKey[keyid], keylen); + psetkeyparm->grpkey = 1; + break; + default: + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("\n rtw_set_key23a:psecuritypriv->dot11PrivacyAlgrthm = " + "%x (must be 1 or 2 or 4 or 5)\n", + psecuritypriv->dot11PrivacyAlgrthm)); + res = _FAIL; + goto exit; + } + + pcmd->cmdcode = _SetKey_CMD_; + pcmd->parmbuf = (u8 *)psetkeyparm; + pcmd->cmdsz = (sizeof(struct setkey_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + INIT_LIST_HEAD(&pcmd->list); + + /* sema_init(&pcmd->cmd_sem, 0); */ + + res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); + +exit: + + return res; +} + +/* adjust IEs for rtw_joinbss_cmd23a in WMM */ +int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint initial_out_len) +{ + unsigned int ielength = 0; + unsigned int i, j; + + i = 12; /* after the fixed IE */ + while(i < in_len) { + ielength = initial_out_len; + + /* WMM element ID and OUI */ + if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && + in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && + in_ie[i + 5] == 0x02 && i+5 < in_len) { + + /* Append WMM IE to the last index of out_ie */ + for (j = i; j < i + 9; j++) { + out_ie[ielength] = in_ie[j]; + ielength++; + } + out_ie[initial_out_len + 1] = 0x07; + out_ie[initial_out_len + 6] = 0x00; + out_ie[initial_out_len + 8] = 0x00; + + break; + } + + i += (in_ie[i + 1] + 2); /* to the next IE element */ + } + + return ielength; +} + +/* */ +/* Ported from 8185: IsInPreAuthKeyList(). + (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */ +/* Added by Annie, 2006-05-07. */ +/* */ +/* Search by BSSID, */ +/* Return Value: */ +/* -1 :if there is no pre-auth key in the table */ +/* >= 0 :if there is pre-auth key, and return the entry id */ +/* */ +/* */ + +static int SecIsInPMKIDList(struct rtw_adapter *Adapter, u8 *bssid) +{ + struct security_priv *psecuritypriv = &Adapter->securitypriv; + int i = 0; + + do { + if (psecuritypriv->PMKIDList[i].bUsed && + ether_addr_equal(psecuritypriv->PMKIDList[i].Bssid, bssid)) { + break; + } else { + i++; + /* continue; */ + } + } while(i < NUM_PMKID_CACHE); + + if (i == NUM_PMKID_CACHE) { + i = -1;/* Could not find. */ + } else { + /* There is one Pre-Authentication Key for + the specific BSSID. */ + } + + return i; +} + +/* */ +/* Check the RSN IE length */ +/* If the RSN IE length <= 20, the RSN IE didn't include + the PMKID information */ +/* 0-11th element in the array are the fixed IE */ +/* 12th element in the array is the IE */ +/* 13th element in the array is the IE length */ +/* */ + +static int rtw_append_pmkid(struct rtw_adapter *Adapter, int iEntry, + u8 *ie, uint ie_len) +{ + struct security_priv *psecuritypriv = &Adapter->securitypriv; + + if (ie[13] <= 20) { + /* The RSN IE didn't include the PMK ID, + append the PMK information */ + ie[ie_len] = 1; + ie_len++; + ie[ie_len] = 0; /* PMKID count = 0x0100 */ + ie_len++; + memcpy(&ie[ie_len], + &psecuritypriv->PMKIDList[iEntry].PMKID, 16); + + ie_len += 16; + ie[13] += 18;/* PMKID length = 2+16 */ + } + return ie_len; +} +int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, + uint in_len) +{ + u8 authmode; + uint ielength; + int iEntry; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct security_priv *psecuritypriv = &adapter->securitypriv; + uint ndisauthmode = psecuritypriv->ndisauthtype; + uint ndissecuritytype = psecuritypriv->ndisencryptstatus; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("+rtw_restruct_sec_ie23a: ndisauthmode=%d ndissecuritytype=%d\n", + ndisauthmode, ndissecuritytype)); + + /* copy fixed ie only */ + memcpy(out_ie, in_ie, 12); + ielength = 12; + if ((ndisauthmode==Ndis802_11AuthModeWPA) || + (ndisauthmode==Ndis802_11AuthModeWPAPSK)) + authmode=_WPA_IE_ID_; + if ((ndisauthmode==Ndis802_11AuthModeWPA2) || + (ndisauthmode==Ndis802_11AuthModeWPA2PSK)) + authmode=_WPA2_IE_ID_; + + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + memcpy(out_ie + ielength, psecuritypriv->wps_ie, + psecuritypriv->wps_ie_len); + + ielength += psecuritypriv->wps_ie_len; + } else if ((authmode==_WPA_IE_ID_) || (authmode==_WPA2_IE_ID_)) { + /* copy RSN or SSN */ + memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], + psecuritypriv->supplicant_ie[1] + 2); + ielength += psecuritypriv->supplicant_ie[1] + 2; + rtw_report_sec_ie23a(adapter, authmode, + psecuritypriv->supplicant_ie); + } + + iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); + if (iEntry < 0) { + return ielength; + } else { + if (authmode == _WPA2_IE_ID_) { + ielength=rtw_append_pmkid(adapter, iEntry, + out_ie, ielength); + } + } + + return ielength; +} + +void rtw_init_registrypriv_dev_network23a(struct rtw_adapter* adapter) +{ + struct registry_priv* pregistrypriv = &adapter->registrypriv; + struct eeprom_priv* peepriv = &adapter->eeprompriv; + struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; + u8 *myhwaddr = myid(peepriv); + + ether_addr_copy(pdev_network->MacAddress, myhwaddr); + + memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, + sizeof(struct cfg80211_ssid)); + + pdev_network->Configuration.Length=sizeof(struct ndis_802_11_config); + pdev_network->Configuration.BeaconPeriod = 100; + pdev_network->Configuration.FHConfig.Length = 0; + pdev_network->Configuration.FHConfig.HopPattern = 0; + pdev_network->Configuration.FHConfig.HopSet = 0; + pdev_network->Configuration.FHConfig.DwellTime = 0; + +} + +void rtw_update_registrypriv_dev_network23a(struct rtw_adapter* adapter) +{ + int sz = 0; + struct registry_priv* pregistrypriv = &adapter->registrypriv; + struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; + /* struct xmit_priv *pxmitpriv = &adapter->xmitpriv; */ + + pdev_network->Privacy = + (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); + + pdev_network->Rssi = 0; + + switch (pregistrypriv->wireless_mode) + { + case WIRELESS_11B: + pdev_network->NetworkTypeInUse = Ndis802_11DS; + break; + case WIRELESS_11G: + case WIRELESS_11BG: + case WIRELESS_11_24N: + case WIRELESS_11G_24N: + case WIRELESS_11BG_24N: + pdev_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + case WIRELESS_11A: + case WIRELESS_11A_5N: + pdev_network->NetworkTypeInUse = Ndis802_11OFDM5; + break; + case WIRELESS_11ABGN: + if (pregistrypriv->channel > 14) + pdev_network->NetworkTypeInUse = Ndis802_11OFDM5; + else + pdev_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + default : + /* TODO */ + break; + } + + pdev_network->Configuration.DSConfig = pregistrypriv->channel; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("pregistrypriv->channel =%d, pdev_network->Configuration." + "DSConfig = 0x%x\n", pregistrypriv->channel, + pdev_network->Configuration.DSConfig)); + + if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) + pdev_network->Configuration.ATIMWindow = 0; + + pdev_network->InfrastructureMode = + cur_network->network.InfrastructureMode; + + /* 1. Supported rates */ + /* 2. IE */ + + sz = rtw_generate_ie23a(pregistrypriv); + + pdev_network->IELength = sz; + + pdev_network->Length = + get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); + + /* notes: translate IELength & Length after assign the + Length to cmdsz in createbss_cmd(); */ + /* pdev_network->IELength = cpu_to_le32(sz); */ + +} + +void rtw_get_encrypt_decrypt_from_registrypriv23a(struct rtw_adapter* adapter) +{ + +} + +/* the fucntion is at passive_level */ +void rtw_joinbss_reset23a(struct rtw_adapter *padapter) +{ + u8 threshold; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + /* todo: if you want to do something io/reg/hw setting + before join_bss, please add code here */ + + pmlmepriv->num_FortyMHzIntolerant = 0; + + pmlmepriv->num_sta_no_ht = 0; + + phtpriv->ampdu_enable = false;/* reset to disabled */ + + /* TH = 1 => means that invalidate usb rx aggregation */ + /* TH = 0 => means that validate usb rx aggregation, use init value. */ + if (phtpriv->ht_option) { + if (padapter->registrypriv.wifi_spec == 1) + threshold = 1; + else + threshold = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, + (u8 *)(&threshold)); + } else { + threshold = 1; + rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, + (u8 *)(&threshold)); + } +} + +/* the fucntion is >= passive_level */ +unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint *pout_len) +{ + u32 ielen, out_len; + int max_rx_ampdu_factor; + unsigned char *p, *pframe; + struct ieee80211_ht_cap ht_capie; + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + phtpriv->ht_option = false; + + p = rtw_get_ie23a(in_ie + 12, _HT_CAPABILITY_IE_, &ielen, in_len - 12); + + if (p && ielen > 0) { + u32 rx_packet_offset, max_recvbuf_sz; + if (pqospriv->qos_option == 0) { + out_len = *pout_len; + pframe = rtw_set_ie23a(out_ie + out_len, + _VENDOR_SPECIFIC_IE_, + _WMM_IE_Length_, WMM_IE, pout_len); + + pqospriv->qos_option = 1; + } + + out_len = *pout_len; + + memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); + + ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | IEEE80211_HT_CAP_DSSSCCK40; + + rtw_hal_get_def_var23a(padapter, HAL_DEF_RX_PACKET_OFFSET, + &rx_packet_offset); + rtw_hal_get_def_var23a(padapter, HAL_DEF_MAX_RECVBUF_SZ, + &max_recvbuf_sz); + + rtw_hal_get_def_var23a(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, + &max_rx_ampdu_factor); + ht_capie.ampdu_params_info = max_rx_ampdu_factor & 0x03; + + if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) + ht_capie.ampdu_params_info |= + (IEEE80211_HT_AMPDU_PARM_DENSITY& (0x07 << 2)); + else + ht_capie.ampdu_params_info |= + (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00); + + pframe = rtw_set_ie23a(out_ie + out_len, _HT_CAPABILITY_IE_, + sizeof(struct ieee80211_ht_cap), + (unsigned char*)&ht_capie, pout_len); + + phtpriv->ht_option = true; + + p = rtw_get_ie23a(in_ie + 12, _HT_ADD_INFO_IE_, &ielen, in_len-12); + if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { + out_len = *pout_len; + pframe = rtw_set_ie23a(out_ie + out_len, _HT_ADD_INFO_IE_, + ielen, p + 2 , pout_len); + } + } + + return phtpriv->ht_option; +} + +/* the fucntion is > passive_level (in critical_section) */ +void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len) +{ + u8 *p, max_ampdu_sz; + int len; + /* struct sta_info *bmc_sta, *psta; */ + struct ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_addt_info *pht_addtinfo; + /* struct recv_reorder_ctrl *preorder_ctrl; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + /* struct recv_priv *precvpriv = &padapter->recvpriv; */ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + /* struct wlan_network *pcur_network = &pmlmepriv->cur_network;; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (!phtpriv->ht_option) + return; + + if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) + return; + + DBG_8723A("+rtw_update_ht_cap23a()\n"); + + /* maybe needs check if ap supports rx ampdu. */ + if ((phtpriv->ampdu_enable == false) && (pregistrypriv->ampdu_enable == 1)) { + if (pregistrypriv->wifi_spec == 1) + phtpriv->ampdu_enable = false; + else + phtpriv->ampdu_enable = true; + } else if (pregistrypriv->ampdu_enable == 2) { + phtpriv->ampdu_enable = true; + } + + /* check Max Rx A-MPDU Size */ + len = 0; + p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_CAPABILITY_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies)); + if (p && len > 0) { + pht_capie = (struct ieee80211_ht_cap *)(p+2); + max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR); + max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ + + /* DBG_8723A("rtw_update_ht_cap23a(): max_ampdu_sz =%d\n", max_ampdu_sz); */ + phtpriv->rx_ampdu_maxlen = max_ampdu_sz; + + } + + len = 0; + p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_ADD_INFO_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies)); + if (p && len>0) + { + pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2); + /* todo: */ + } + + /* update cur_bwmode & cur_ch_offset */ + if ((pregistrypriv->cbw40_enable) && + (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && + (pmlmeinfo->HT_info.infos[0] & BIT(2))) + { + int i; + u8 rf_type; + + padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + + /* update the MCS rates */ + for (i = 0; i < 16; i++) + { + if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R23A[i]; + else + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R23A[i]; + } + /* switch to the 40M Hz mode accoring to the AP */ + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; + switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) + { + case HT_EXTCHNL_OFFSET_UPPER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case HT_EXTCHNL_OFFSET_LOWER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } + + /* */ + /* Config SM Power Save setting */ + /* */ + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) + DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); + + /* */ + /* Config current HT Protection mode. */ + /* */ + pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; +} + +void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + u8 issued; + int priority; + struct sta_info *psta = NULL; + struct ht_priv *phtpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + s32 bmcst = is_multicast_ether_addr(pattrib->ra); + + if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod<100)) + return; + + priority = pattrib->priority; + + if (pattrib->psta) + psta = pattrib->psta; + else + { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra); + } + + if (psta == NULL) + { + DBG_8723A("%s, psta == NUL\n", __func__); + return; + } + + if (!(psta->state &_FW_LINKED)) + { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return; + } + + phtpriv = &psta->htpriv; + + if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true)) + { + issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; + issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; + + if (0 == issued) + { + DBG_8723A("rtw_issue_addbareq_cmd23a, p =%d\n", priority); + psta->htpriv.candidate_tid_bitmap |= CHKBIT((u8)priority); + rtw_addbareq_cmd23a(padapter, (u8) priority, pattrib->ra); + } + } +} + +inline void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming) +{ + if (to_roaming == 0) + adapter->mlmepriv.to_join = false; + adapter->mlmepriv.to_roaming = to_roaming; +} + +inline u8 rtw_to_roaming(struct rtw_adapter *adapter) +{ + return adapter->mlmepriv.to_roaming; +} + +void rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + spin_lock_bh(&pmlmepriv->lock); + _rtw23a_roaming(padapter, tgt_network); + spin_unlock_bh(&pmlmepriv->lock); +} +void _rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork; + int do_join_r; + + if (tgt_network != NULL) + pnetwork = tgt_network; + else + pnetwork = &pmlmepriv->cur_network; + + if (0 < rtw_to_roaming(padapter)) { + DBG_8723A("roaming from %s("MAC_FMT"), length:%d\n", + pnetwork->network.Ssid.ssid, + MAC_ARG(pnetwork->network.MacAddress), + pnetwork->network.Ssid.ssid_len); + memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, + sizeof(struct cfg80211_ssid)); + + pmlmepriv->assoc_by_bssid = false; + + while(1) { + if (_SUCCESS == (do_join_r = rtw_do_join23a(padapter))) { + break; + } else { + DBG_8723A("roaming do_join return %d\n", do_join_r); + pmlmepriv->to_roaming--; + + if (0 < rtw_to_roaming(padapter)) { + continue; + } else { + DBG_8723A("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); + rtw_indicate_disconnect23a(padapter); + break; + } + } + } + } +} + +int rtw_linked_check(struct rtw_adapter *padapter) +{ + if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) || + (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))) { + if (padapter->stapriv.asoc_sta_count > 2) + return true; + } else { /* Station mode */ + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == true) + return true; + } + return false; +} diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c new file mode 100644 index 000000000000..75ccdec881e5 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c @@ -0,0 +1,9988 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_MLME_EXT_C_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_8723AU_BT_COEXIST +#include +#endif + +static struct mlme_handler mlme_sta_tbl[]={ + {"OnAssocReq23a", &OnAssocReq23a}, + {"OnAssocRsp23a", &OnAssocRsp23a}, + {"OnReAssocReq", &OnAssocReq23a}, + {"OnReAssocRsp", &OnAssocRsp23a}, + {"OnProbeReq23a", &OnProbeReq23a}, + {"OnProbeRsp23a", &OnProbeRsp23a}, + + /*---------------------------------------------------------- + below 2 are reserved + -----------------------------------------------------------*/ + {"DoReserved23a", &DoReserved23a}, + {"DoReserved23a", &DoReserved23a}, + {"OnBeacon23a", &OnBeacon23a}, + {"OnATIM", &OnAtim23a}, + {"OnDisassoc23a", &OnDisassoc23a}, + {"OnAuth23a", &OnAuth23aClient23a}, + {"OnDeAuth23a", &OnDeAuth23a}, + {"OnAction23a", &OnAction23a}, +}; + +static struct action_handler OnAction23a_tbl[]={ + {WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct23a}, + {WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction23a_qos}, + {WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction23a_dls}, + {WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction23a_back23a}, + {WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public23a}, + {WLAN_CATEGORY_HT, "ACTION_HT", &OnAction23a_ht}, + {WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved23a}, + {WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction23a_wmm}, + {WLAN_CATEGORY_VENDOR_SPECIFIC, "ACTION_P2P", &OnAction23a_p2p}, +}; + +static u8 null_addr[ETH_ALEN]= {0, 0, 0, 0, 0, 0}; + +/************************************************** +OUI definitions for the vendor specific IE +***************************************************/ +unsigned char RTW_WPA_OUI23A[] = {0x00, 0x50, 0xf2, 0x01}; +unsigned char WMM_OUI23A[] = {0x00, 0x50, 0xf2, 0x02}; +unsigned char WPS_OUI23A[] = {0x00, 0x50, 0xf2, 0x04}; +unsigned char P2P_OUI23A[] = {0x50, 0x6F, 0x9A, 0x09}; +unsigned char WFD_OUI23A[] = {0x50, 0x6F, 0x9A, 0x0A}; + +unsigned char WMM_INFO_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; +unsigned char WMM_PARA_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + +unsigned char WPA_TKIP_CIPHER23A[4] = {0x00, 0x50, 0xf2, 0x02}; +unsigned char RSN_TKIP_CIPHER23A[4] = {0x00, 0x0f, 0xac, 0x02}; + + +/******************************************************** +MCS rate definitions +*********************************************************/ +unsigned char MCS_rate_2R23A[16] = { + 0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; +unsigned char MCS_rate_1R23A[16] = { + 0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + +/******************************************************** +ChannelPlan definitions +*********************************************************/ + +static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */ + {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */ + {{}, 0}, /* 0x05, RT_CHANNEL_DOMAIN_2G_NULL */ +}; + +static struct rt_channel_plan_5g RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = { + {{}, 0}, /* 0x00, RT_CHANNEL_DOMAIN_5G_NULL */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165}, 22}, /* 0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x04, RT_CHANNEL_DOMAIN_5G_FCC1 */ + {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9}, /* 0x05, RT_CHANNEL_DOMAIN_5G_FCC2 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13}, /* 0x06, RT_CHANNEL_DOMAIN_5G_FCC3 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 12}, /* 0x07, RT_CHANNEL_DOMAIN_5G_FCC4 */ + {{149, 153, 157, 161, 165}, 5}, /* 0x08, RT_CHANNEL_DOMAIN_5G_FCC5 */ + {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x09, RT_CHANNEL_DOMAIN_5G_FCC6 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20}, /* 0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 20}, /* 0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 */ + {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 */ + {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11}, /* 0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 */ + {{56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 15}, /* 0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 */ + {{56, 60, 64, 149, 153, 157, 161, 165}, 8}, /* 0x10, RT_CHANNEL_DOMAIN_5G_NCC2 */ + + /* Driver self defined for old channel plan Compatible , Remember to modify if have new channel plan definition ===== */ + {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 21}, /* 0x11, RT_CHANNEL_DOMAIN_5G_FCC */ + {{36, 40, 44, 48}, 4}, /* 0x12, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS */ + {{36, 40, 44, 48, 149, 153, 157, 161}, 8}, /* 0x13, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */ +}; + +static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { + /* 0x00 ~ 0x1F , Old Define ===== */ + {0x02, 0x11}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ + {0x02, 0x0A}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ + {0x01, 0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */ + {0x01, 0x00}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */ + {0x01, 0x00}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */ + {0x03, 0x00}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */ + {0x03, 0x00}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */ + {0x01, 0x09}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */ + {0x03, 0x09}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */ + {0x03, 0x00}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */ + {0x00, 0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */ + {0x02, 0x0F}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */ + {0x01, 0x08}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */ + {0x02, 0x06}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */ + {0x02, 0x0B}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */ + {0x02, 0x09}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */ + {0x01, 0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */ + {0x02, 0x05}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */ + {0x01, 0x12}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ + {0x00, 0x04}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */ + {0x02, 0x10}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */ + {0x00, 0x12}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */ + {0x00, 0x13}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */ + {0x03, 0x12}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ + {0x05, 0x08}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */ + {0x02, 0x08}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */ + {0x00, 0x00}, /* 0x1A, */ + {0x00, 0x00}, /* 0x1B, */ + {0x00, 0x00}, /* 0x1C, */ + {0x00, 0x00}, /* 0x1D, */ + {0x00, 0x00}, /* 0x1E, */ + {0x05, 0x04}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */ + /* 0x20 ~ 0x7F , New Define ===== */ + {0x00, 0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */ + {0x01, 0x00}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */ + {0x02, 0x00}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */ + {0x03, 0x00}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */ + {0x04, 0x00}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */ + {0x02, 0x04}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */ + {0x00, 0x01}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */ + {0x03, 0x0C}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */ + {0x00, 0x0B}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */ + {0x00, 0x05}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */ + {0x00, 0x00}, /* 0x2A, */ + {0x00, 0x00}, /* 0x2B, */ + {0x00, 0x00}, /* 0x2C, */ + {0x00, 0x00}, /* 0x2D, */ + {0x00, 0x00}, /* 0x2E, */ + {0x00, 0x00}, /* 0x2F, */ + {0x00, 0x06}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */ + {0x00, 0x07}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */ + {0x00, 0x08}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */ + {0x00, 0x09}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */ + {0x02, 0x0A}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */ + {0x00, 0x02}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */ + {0x00, 0x03}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */ + {0x03, 0x0D}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */ + {0x03, 0x0E}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */ + {0x02, 0x0F}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */ + {0x00, 0x00}, /* 0x3A, */ + {0x00, 0x00}, /* 0x3B, */ + {0x00, 0x00}, /* 0x3C, */ + {0x00, 0x00}, /* 0x3D, */ + {0x00, 0x00}, /* 0x3E, */ + {0x00, 0x00}, /* 0x3F, */ + {0x02, 0x10}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */ + {0x03, 0x00}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */ +}; + +static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; /* use the conbination for max channel numbers */ + +static struct fwevent wlanevents[] = +{ + {0, rtw_dummy_event_callback23a}, /*0*/ + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, &rtw_survey_event_cb23a}, /*8*/ + {sizeof (struct surveydone_event), &rtw_surveydone_event_callback23a}, /*9*/ + + {0, &rtw23a_joinbss_event_cb}, /*10*/ + {sizeof(struct stassoc_event), &rtw_stassoc_event_callback23a}, + {sizeof(struct stadel_event), &rtw_stadel_event_callback23a}, + {0, &rtw_atimdone_event_callback23a}, + {0, rtw_dummy_event_callback23a}, + {0, NULL}, /*15*/ + {0, NULL}, + {0, NULL}, + {0, NULL}, + {0, rtw23a_fwdbg_event_callback}, + {0, NULL}, /*20*/ + {0, NULL}, + {0, NULL}, + {0, &rtw_cpwm_event_callback23a}, + {0, NULL}, +}; + + +/* + * Search the @param channel_num in given @param channel_set + * @ch_set: the given channel set + * @ch: the given channel number + * + * return the index of channel_num in channel_set, -1 if not found + */ +int rtw_ch_set_search_ch23a(struct rt_channel_info *ch_set, const u32 ch) +{ + int i; + for (i = 0; ch_set[i]. ChannelNum != 0; i++) { + if (ch == ch_set[i].ChannelNum) + break; + } + + if (i >= ch_set[i].ChannelNum) + return -1; + return i; +} + +/**************************************************************************** + +Following are the initialization functions for WiFi MLME + +*****************************************************************************/ + +int init_hw_mlme_ext23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, + pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + return _SUCCESS; +} + +static void init_mlme_ext_priv23a_value(struct rtw_adapter* padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + unsigned char mixed_datarate[NumRates] = { + _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, + _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, + _48M_RATE_, _54M_RATE_, 0xff}; + unsigned char mixed_basicrate[NumRates] = { + _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, + _12M_RATE_, _24M_RATE_, 0xff,}; + + atomic_set(&pmlmeext->event_seq, 0); + /* reset to zero when disconnect at client mode */ + pmlmeext->mgnt_seq = 0; + + pmlmeext->cur_channel = padapter->registrypriv.channel; + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + pmlmeext->retry = 0; + + pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; + + memcpy(pmlmeext->datarate, mixed_datarate, NumRates); + memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); + + if (pmlmeext->cur_channel > 14) + pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB; + else + pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; + + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + pmlmeext->sitesurvey_res.channel_idx = 0; + pmlmeext->sitesurvey_res.bss_cnt = 0; + pmlmeext->scan_abort = false; + + pmlmeinfo->state = WIFI_FW_NULL_STATE; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeinfo->auth_seq = 0; + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + pmlmeinfo->key_index = 0; + pmlmeinfo->iv = 0; + + pmlmeinfo->enc_algo = _NO_PRIVACY_; + pmlmeinfo->authModeToggle = 0; + + memset(pmlmeinfo->chg_txt, 0, 128); + + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + pmlmeinfo->preamble_mode = PREAMBLE_AUTO; + + pmlmeinfo->dialogToken = 0; + + pmlmeext->action_public_rxseq = 0xffff; + pmlmeext->action_public_dialog_token = 0xff; +} + +static int has_channel(struct rt_channel_info *channel_set, + u8 chanset_size, u8 chan) { + int i; + + for (i = 0; i < chanset_size; i++) { + if (channel_set[i].ChannelNum == chan) + return 1; + } + + return 0; +} + +static void init_channel_list(struct rtw_adapter *padapter, + struct rt_channel_info *channel_set, + u8 chanset_size, + struct p2p_channels *channel_list) { + + struct p2p_oper_class_map op_class[] = { + { IEEE80211G, 81, 1, 13, 1, BW20 }, + { IEEE80211G, 82, 14, 14, 1, BW20 }, + { IEEE80211A, 115, 36, 48, 4, BW20 }, + { IEEE80211A, 116, 36, 44, 8, BW40PLUS }, + { IEEE80211A, 117, 40, 48, 8, BW40MINUS }, + { IEEE80211A, 124, 149, 161, 4, BW20 }, + { IEEE80211A, 125, 149, 169, 4, BW20 }, + { IEEE80211A, 126, 149, 157, 8, BW40PLUS }, + { IEEE80211A, 127, 153, 161, 8, BW40MINUS }, + { -1, 0, 0, 0, 0, BW20 } + }; + + int cla, op; + + cla = 0; + + for (op = 0; op_class[op].op_class; op++) { + u8 ch; + struct p2p_oper_class_map *o = &op_class[op]; + struct p2p_reg_class *reg = NULL; + + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + if (!has_channel(channel_set, chanset_size, ch)) + continue; + + if ((0 == padapter->registrypriv.ht_enable) && + (o->inc == 8)) + continue; + + if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && + ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) + continue; + + if (reg == NULL) { + reg = &channel_list->reg_class[cla]; + cla++; + reg->reg_class = o->op_class; + reg->channels = 0; + } + reg->channel[reg->channels] = ch; + reg->channels++; + } + } + channel_list->reg_classes = cla; +} + +static u8 init_channel_set(struct rtw_adapter* padapter, u8 ChannelPlan, + struct rt_channel_info *channel_set) +{ + u8 index, chanset_size = 0; + u8 b5GBand = false, b2_4GBand = false; + u8 Index2G = 0, Index5G = 0; + + memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM); + + if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && + ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { + DBG_8723A("ChannelPlan ID %x error !!!!!\n", ChannelPlan); + return chanset_size; + } + + if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { + b2_4GBand = true; + if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) + Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; + else + Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; + } + + if (padapter->registrypriv.wireless_mode & WIRELESS_11A) { + b5GBand = true; + if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) + Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G; + else + Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G; + } + + if (b2_4GBand) { + for (index = 0; index= 1 && + channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = + SCAN_ACTIVE; + else if ((channel_set[chanset_size].ChannelNum >= 12 && + channel_set[chanset_size].ChannelNum <= 14)) + channel_set[chanset_size].ScanType = + SCAN_PASSIVE; + } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == + ChannelPlan || + RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == + ChannelPlan || + RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) { + /* channel 12~13, passive scan */ + if (channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = + SCAN_ACTIVE; + else + channel_set[chanset_size].ScanType = + SCAN_PASSIVE; + } else + channel_set[chanset_size].ScanType = + SCAN_ACTIVE; + + chanset_size++; + } + } + + if (b5GBand) { + for (index = 0;index= 149) { + channel_set[chanset_size].ChannelNum = + RTW_ChannelPlan5G[Index5G].Channel[index]; + if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == + ChannelPlan) { + /* passive scan for all 5G channels */ + channel_set[chanset_size].ScanType = + SCAN_PASSIVE; + } else + channel_set[chanset_size].ScanType = + SCAN_ACTIVE; + DBG_8723A("%s(): channel_set[%d].ChannelNum = " + "%d\n", __func__, chanset_size, + channel_set[chanset_size].ChannelNum); + chanset_size++; + } + } + } + + return chanset_size; +} + +int init_mlme_ext_priv23a(struct rtw_adapter* padapter) +{ + int res = _SUCCESS; + struct registry_priv* pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + pmlmeext->padapter = padapter; + + init_mlme_ext_priv23a_value(padapter); + pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; + + init_mlme_ext_timer23a(padapter); + +#ifdef CONFIG_8723AU_AP_MODE + init_mlme_ap_info23a(padapter); +#endif + + pmlmeext->max_chan_nums = init_channel_set(padapter, + pmlmepriv->ChannelPlan, + pmlmeext->channel_set); + init_channel_list(padapter, pmlmeext->channel_set, + pmlmeext->max_chan_nums, &pmlmeext->channel_list); + + pmlmeext->chan_scan_time = SURVEY_TO; + pmlmeext->mlmeext_init = true; + + pmlmeext->active_keep_alive_check = true; + return res; +} + +void free_mlme_ext_priv23a (struct mlme_ext_priv *pmlmeext) +{ + struct rtw_adapter *padapter = pmlmeext->padapter; + + if (!padapter) + return; + + if (padapter->bDriverStopped == true) { + del_timer_sync(&pmlmeext->survey_timer); + del_timer_sync(&pmlmeext->link_timer); + /* del_timer_sync(&pmlmeext->ADDBA_timer); */ + } +} + +static void +_mgt_dispatcher23a(struct rtw_adapter *padapter, struct mlme_handler *ptable, + struct recv_frame *precv_frame) +{ + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (ptable->func) { + /* receive the frames that ra(a1) is my address + or ra(a1) is bc address. */ + if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv))&& + !is_broadcast_ether_addr(hdr->addr1)) + return; + + ptable->func(padapter, precv_frame); + } +} + +void mgt_dispatcher23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + int index; + struct mlme_handler *ptable; +#ifdef CONFIG_8723AU_AP_MODE + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif /* CONFIG_8723AU_AP_MODE */ + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 stype; + struct sta_info *psta; + + if (!ieee80211_is_mgmt(hdr->frame_control)) + return; + + /* receive the frames that ra(a1) is my address or ra(a1) is + bc address. */ + if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv)) && + !is_broadcast_ether_addr(hdr->addr1)) + return; + + ptable = mlme_sta_tbl; + + stype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; + index = stype >> 4; + + if (index > 13) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("Currently we do not support reserved sub-fr-type =" + "%d\n", index)); + return; + } + ptable += index; + + psta = rtw_get_stainfo23a(&padapter->stapriv, hdr->addr2); + + if (psta) { + if (ieee80211_has_retry(hdr->frame_control)) { + if (precv_frame->attrib.seq_num == + psta->RxMgmtFrameSeqNum) { + /* drop the duplicate management frame */ + DBG_8723A("Drop duplicate management frame " + "with seq_num = %d.\n", + precv_frame->attrib.seq_num); + return; + } + } + psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num; + } + +#ifdef CONFIG_8723AU_AP_MODE + switch (stype) + { + case IEEE80211_STYPE_AUTH: + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + ptable->func = &OnAuth23a; + else + ptable->func = &OnAuth23aClient23a; + /* pass through */ + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + _mgt_dispatcher23a(padapter, ptable, precv_frame); + break; + case IEEE80211_STYPE_PROBE_REQ: + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + _mgt_dispatcher23a(padapter, ptable, precv_frame); + else + _mgt_dispatcher23a(padapter, ptable, precv_frame); + break; + case IEEE80211_STYPE_BEACON: + _mgt_dispatcher23a(padapter, ptable, precv_frame); + break; + case IEEE80211_STYPE_ACTION: + /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) */ + _mgt_dispatcher23a(padapter, ptable, precv_frame); + break; + default: + _mgt_dispatcher23a(padapter, ptable, precv_frame); + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + rtw_hostapd_mlme_rx23a(padapter, precv_frame); + break; + } +#else + _mgt_dispatcher23a(padapter, ptable, precv_frame); +#endif +} + +#ifdef CONFIG_8723AU_P2P +static u32 p2p_listen_state_process(struct rtw_adapter *padapter, + unsigned char *da) +{ + bool response = true; + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == false || + padapter->mlmepriv.wps_probe_resp_ie == NULL || + padapter->mlmepriv.p2p_probe_resp_ie == NULL) { + DBG_8723A("DON'T issue_probersp23a_p2p23a: p2p_enabled:%d, " + "wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p\n", + wdev_to_priv(padapter->rtw_wdev)->p2p_enabled, + padapter->mlmepriv.wps_probe_resp_ie, + padapter->mlmepriv.p2p_probe_resp_ie); + response = false; + } + + if (response == true) + issue_probersp23a_p2p23a(padapter, da); + + return _SUCCESS; +} +#endif /* CONFIG_8723AU_P2P */ + +/**************************************************************************** + +Following are the callback functions for each subtype of the management frames + +*****************************************************************************/ + +unsigned int OnProbeReq23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + unsigned int ielen; + unsigned char *p; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur = &pmlmeinfo->network; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint len = skb->len; + u8 is_valid_p2p_probereq = false; + +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 wifi_test_chk_rate = 1; + + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && + !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) { + /* mcs_rate = 0 -> CCK 1M rate */ + /* mcs_rate = 1 -> CCK 2M rate */ + /* mcs_rate = 2 -> CCK 5.5M rate */ + /* mcs_rate = 3 -> CCK 11M rate */ + /* In the P2P mode, the driver should not support + the CCK rate */ + + /* IOT issue: Google Nexus7 use 1M rate to send + p2p_probe_req after GO nego completed and Nexus7 + is client */ + if (wifi_test_chk_rate == 1) { + if ((is_valid_p2p_probereq = + process_probe_req_p2p_ie23a(pwdinfo, pframe, + len)) == true) { + if (rtw_p2p_chk_role(pwdinfo, + P2P_ROLE_DEVICE)) { + u8 *sa = ieee80211_get_SA(hdr); + p2p_listen_state_process(padapter, sa); + return _SUCCESS; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + goto _continue; + } + } + } + } + +_continue: +#endif /* CONFIG_8723AU_P2P */ + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + return _SUCCESS; + } + + if (check_fwstate(pmlmepriv, _FW_LINKED) == false && + check_fwstate(pmlmepriv, + WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == false) { + return _SUCCESS; + } + + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, + len - sizeof(struct ieee80211_hdr_3addr) - + _PROBEREQ_IE_OFFSET_); + + /* check (wildcard) SSID */ + if (p) { + if (is_valid_p2p_probereq == true) { + goto _issue_probersp23a; + } + + if ((ielen != 0 && + memcmp((void *)(p+2), cur->Ssid.ssid, + cur->Ssid.ssid_len)) || + (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) { + return _SUCCESS; + } + +_issue_probersp23a: + + if (check_fwstate(pmlmepriv, _FW_LINKED) == true && + pmlmepriv->cur_network.join_res == true) { + /* DBG_8723A("+issue_probersp23a during ap mode\n"); */ + issue_probersp23a(padapter, ieee80211_get_SA(hdr), + is_valid_p2p_probereq); + } + } + + return _SUCCESS; +} + +unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { + if (pwdinfo->tx_prov_disc_info.benable == true) { + if (ether_addr_equal(pwdinfo->tx_prov_disc_info.peerIFAddr, + hdr->addr2)) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + pwdinfo->tx_prov_disc_info.benable = false; + issue_p2p_provision_request23a(padapter, + pwdinfo->tx_prov_disc_info.ssid.ssid, + pwdinfo->tx_prov_disc_info.ssid.ssid_len, + pwdinfo->tx_prov_disc_info.peerDevAddr); + } + else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + pwdinfo->tx_prov_disc_info.benable = false; + issue_p2p_provision_request23a(padapter, + NULL, + 0, + pwdinfo->tx_prov_disc_info.peerDevAddr); + } + } + } + return _SUCCESS; + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { + if (pwdinfo->nego_req_info.benable == true) { + DBG_8723A("[%s] P2P State is GONEGO ING!\n", __func__); + if (ether_addr_equal(pwdinfo->nego_req_info.peerDevAddr, + hdr->addr2)) { + pwdinfo->nego_req_info.benable = false; + issue_p2p_GO_request23a(padapter, pwdinfo->nego_req_info.peerDevAddr); + } + } + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { + if (pwdinfo->invitereq_info.benable == true) { + DBG_8723A("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__); + if (ether_addr_equal( + pwdinfo->invitereq_info.peer_macaddr, + hdr->addr2)) { + pwdinfo->invitereq_info.benable = false; + issue_p2p_invitation_request23a(padapter, pwdinfo->invitereq_info.peer_macaddr); + } + } + } +#endif + + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + report_survey_event23a(padapter, precv_frame); + return _SUCCESS; + } + + return _SUCCESS; +} + +unsigned int OnBeacon23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + int cam_idx; + struct sta_info *psta; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint len = skb->len; + struct wlan_bssid_ex *pbss; + int ret = _SUCCESS; + u8 *p = NULL; + u32 ielen = 0; + + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen, + len - sizeof(struct ieee80211_hdr_3addr) - + _BEACON_IE_OFFSET_); + if ((p != NULL) && (ielen > 0)) { + if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) { + /* Invalid value 0x2D is detected in Extended Supported + * Rates (ESR) IE. Try to fix the IE length to avoid + * failed Beacon parsing. + */ + DBG_8723A("[WIFIDBG] Error in ESR IE is detected in " + "Beacon of BSSID: %pM. Fix the length of " + "ESR IE to avoid failed Beacon parsing.\n", + hdr->addr3); + *(p + 1) = ielen - 1; + } + } + + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + report_survey_event23a(padapter, precv_frame); + return _SUCCESS; + } + + if (ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))){ + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { + /* we should update current network before auth, + or some IE is wrong */ + pbss = (struct wlan_bssid_ex *) + kmalloc(sizeof(struct wlan_bssid_ex), + GFP_ATOMIC); + if (pbss) { + if (collect_bss_info23a(padapter, precv_frame, + pbss) == _SUCCESS) { + update_network23a(&pmlmepriv->cur_network.network, pbss, padapter, true); + rtw_get_bcn_info23a(&pmlmepriv->cur_network); + } + kfree(pbss); + } + + /* check the vendor of the assoc AP */ + pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pframe + sizeof(struct ieee80211_hdr_3addr), len-sizeof(struct ieee80211_hdr_3addr)); + + /* update TSF Value */ + update_TSF23a(pmlmeext, pframe, len); + + /* start auth */ + start_clnt_auth23a(padapter); + + return _SUCCESS; + } + + if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && + (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + if (psta) { + ret = rtw_check_bcn_info23a(padapter, pframe, + len); + if (!ret) { + DBG_8723A_LEVEL(_drv_always_, + "ap has changed, " + "disconnect now\n"); + receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, 65535); + return _SUCCESS; + } + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of + the number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) { + /* DBG_8723A("update_bcn_info\n"); */ + update_beacon23a_info(padapter, pframe, + len, psta); + } + +#ifdef CONFIG_8723AU_P2P + process_p2p_ps_ie23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr)), (len - sizeof(struct ieee80211_hdr_3addr))); +#endif /* CONFIG_8723AU_P2P */ + } + } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + if (psta) { + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of the + number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) { + /* DBG_8723A("update_bcn_info\n"); */ + update_beacon23a_info(padapter, pframe, + len, psta); + } + } else { + /* allocate a new CAM entry for IBSS station */ + cam_idx = allocate_fw_sta_entry23a(padapter); + if (cam_idx == NUM_STA) + goto _END_ONBEACON_; + + /* get supported rate */ + if (update_sta_support_rate23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_), (len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { + pmlmeinfo->FW_sta_info[cam_idx].status = 0; + goto _END_ONBEACON_; + } + + /* update TSF Value */ + update_TSF23a(pmlmeext, pframe, len); + + /* report sta add event */ + report_add_sta_event23a(padapter, hdr->addr2, + cam_idx); + } + } + } + +_END_ONBEACON_: + + return _SUCCESS; +} + +unsigned int OnAuth23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_AP_MODE + unsigned int auth_mode, seq, ie_len; + unsigned char *sa, *p; + u16 algorithm; + int status; + static struct sta_info stat; + struct sta_info *pstat = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint len = skb->len; + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + DBG_8723A("+OnAuth23a\n"); + + sa = hdr->addr2; + + auth_mode = psecuritypriv->dot11AuthAlgrthm; + seq = cpu_to_le16(*(u16*)((unsigned long)pframe + + sizeof(struct ieee80211_hdr_3addr) + 2)); + algorithm = cpu_to_le16(*(u16*)((unsigned long)pframe + + sizeof(struct ieee80211_hdr_3addr))); + + DBG_8723A("auth alg =%x, seq =%X\n", algorithm, seq); + + if (auth_mode == 2 && + psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && + psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) + auth_mode = 0; + + /* rx a shared-key auth but shared not enabled, or */ + /* rx a open-system auth but shared-key is enabled */ + if ((algorithm > 0 && auth_mode == 0) || + (algorithm == 0 && auth_mode == 1)) { + DBG_8723A("auth rejected due to bad alg [alg =%d, auth_mib " + "=%d] %02X%02X%02X%02X%02X%02X\n", + algorithm, auth_mode, + sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + + status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + + goto auth_fail; + } + + if (rtw_access_ctrl23a(padapter, sa) == false) { + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + goto auth_fail; + } + + pstat = rtw_get_stainfo23a(pstapriv, sa); + if (!pstat) { + /* allocate a new one */ + DBG_8723A("going to alloc stainfo for sa ="MAC_FMT"\n", + MAC_ARG(sa)); + pstat = rtw_alloc_stainfo23a(pstapriv, sa); + if (!pstat) { + DBG_8723A(" Exceed the upper limit of supported " + "clients...\n"); + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + goto auth_fail; + } + + pstat->state = WIFI_FW_AUTH_NULL; + pstat->auth_seq = 0; + + /* pstat->flags = 0; */ + /* pstat->capability = 0; */ + } else { + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&pstat->asoc_list)) { + list_del_init(&pstat->asoc_list); + pstapriv->asoc_list_cnt--; + if (pstat->expire_to > 0) + { + /* TODO: STA re_auth within expire_to */ + } + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + if (seq == 1) { + /* TODO: STA re_auth and auth timeout */ + } + } + + spin_lock_bh(&pstapriv->auth_list_lock); + if (list_empty(&pstat->auth_list)) { + list_add_tail(&pstat->auth_list, &pstapriv->auth_list); + pstapriv->auth_list_cnt++; + } + spin_unlock_bh(&pstapriv->auth_list_lock); + + if (pstat->auth_seq == 0) + pstat->expire_to = pstapriv->auth_to; + + if ((pstat->auth_seq + 1) != seq) { + DBG_8723A("(1)auth rejected because out of seq [rx_seq =%d, " + "exp_seq =%d]!\n", seq, pstat->auth_seq+1); + status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + goto auth_fail; + } + + if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { + if (seq == 1) { + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_SUCCESS; + pstat->expire_to = pstapriv->assoc_to; + pstat->authalg = algorithm; + } else { + DBG_8723A("(2)auth rejected because out of seq " + "[rx_seq =%d, exp_seq =%d]!\n", + seq, pstat->auth_seq+1); + status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + goto auth_fail; + } + } else { /* shared system or auto authentication */ + if (seq == 1) { + /* prepare for the challenging txt... */ + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_STATE; + pstat->authalg = algorithm; + pstat->auth_seq = 2; + } else if (seq == 3) { + /* checking for challenging txt... */ + DBG_8723A("checking for challenging txt...\n"); + + p = rtw_get_ie23a(pframe + + sizeof(struct ieee80211_hdr_3addr) + + 4 + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, + (int *)&ie_len, len - + sizeof(struct ieee80211_hdr_3addr) - + _AUTH_IE_OFFSET_ - 4); + + if ((p == NULL) || (ie_len<= 0)) { + DBG_8723A("auth rejected because challenge " + "failure!(1)\n"); + status = WLAN_STATUS_CHALLENGE_FAIL; + goto auth_fail; + } + + if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { + pstat->state &= (~WIFI_FW_AUTH_STATE); + pstat->state |= WIFI_FW_AUTH_SUCCESS; + /* challenging txt is correct... */ + pstat->expire_to = pstapriv->assoc_to; + } else { + DBG_8723A("auth rejected because challenge " + "failure!\n"); + status = WLAN_STATUS_CHALLENGE_FAIL; + goto auth_fail; + } + } else { + DBG_8723A("(3)auth rejected because out of seq " + "[rx_seq =%d, exp_seq =%d]!\n", + seq, pstat->auth_seq+1); + status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + goto auth_fail; + } + } + + /* Now, we are going to issue_auth23a... */ + pstat->auth_seq = seq + 1; + + issue_auth23a(padapter, pstat, (unsigned short)WLAN_STATUS_SUCCESS); + + if (pstat->state & WIFI_FW_AUTH_SUCCESS) + pstat->auth_seq = 0; + + return _SUCCESS; + +auth_fail: + + if (pstat) + rtw_free_stainfo23a(padapter, pstat); + + pstat = &stat; + memset((char *)pstat, '\0', sizeof(stat)); + pstat->auth_seq = 2; + memcpy(pstat->hwaddr, sa, 6); + + issue_auth23a(padapter, pstat, (unsigned short)status); + +#endif + return _FAIL; +} + +unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + unsigned int seq, len, status, algthm, offset; + unsigned char *p; + unsigned int go2asoc = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint pkt_len = skb->len; + + DBG_8723A("%s\n", __func__); + + /* check A1 matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), + ieee80211_get_DA(hdr))) + return _SUCCESS; + + if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) + return _SUCCESS; + + offset = ieee80211_has_protected(hdr->frame_control) ? 4: 0; + + algthm = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset)); + seq = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 2)); + status = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 4)); + + if (status != 0) + { + DBG_8723A("clnt auth fail, status: %d\n", status); + if (status == 13)/* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ + { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + else + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; + /* pmlmeinfo->reauth_count = 0; */ + } + + set_link_timer(pmlmeext, 1); + goto authclnt_fail; + } + + if (seq == 2) + { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + { + /* legendary shared system */ + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, + pkt_len - sizeof(struct ieee80211_hdr_3addr) - _AUTH_IE_OFFSET_); + + if (p == NULL) + { + /* DBG_8723A("marc: no challenge text?\n"); */ + goto authclnt_fail; + } + + memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); + pmlmeinfo->auth_seq = 3; + issue_auth23a(padapter, NULL, 0); + set_link_timer(pmlmeext, REAUTH_TO); + + return _SUCCESS; + } + else + { + /* open system */ + go2asoc = 1; + } + } + else if (seq == 4) + { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + { + go2asoc = 1; + } + else + { + goto authclnt_fail; + } + } + else + { + /* this is also illegal */ + /* DBG_8723A("marc: clnt auth failed due to illegal seq =%x\n", seq); */ + goto authclnt_fail; + } + + if (go2asoc) + { + DBG_8723A_LEVEL(_drv_always_, "auth success, start assoc\n"); + start_clnt_assoc23a(padapter); + return _SUCCESS; + } + +authclnt_fail: + + /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */ + + return _FAIL; +} + +unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_AP_MODE + u16 capab_info, listen_interval; + struct rtw_ieee802_11_elems elems; + struct sta_info *pstat; + unsigned char reassoc, *p, *pos, *wpa_ie; + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; + int i, ie_len, wpa_ie_len, left; + unsigned char supportRate[16]; + int supportRateNum; + unsigned short status = WLAN_STATUS_SUCCESS; + unsigned short ie_offset; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur = &pmlmeinfo->network; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + uint pkt_len = skb->len; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 frame_control; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 p2p_status_code = P2P_STATUS_SUCCESS; + u8 *p2pie; + u32 p2pielen = 0; + u8 wfd_ie[ 128 ] = { 0x00 }; + u32 wfd_ielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + frame_control = hdr->frame_control; + if (ieee80211_is_assoc_req(frame_control)) { + reassoc = 0; + ie_offset = _ASOCREQ_IE_OFFSET_; + } else { /* WIFI_REASSOCREQ */ + reassoc = 1; + ie_offset = _REASOCREQ_IE_OFFSET_; + } + + if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) { + DBG_8723A("handle_assoc(reassoc =%d) - too short payload (len =%lu)" + "\n", reassoc, (unsigned long)pkt_len); + return _FAIL; + } + + pstat = rtw_get_stainfo23a(pstapriv, hdr->addr2); + if (!pstat) { + status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; + goto asoc_class2_error; + } + + capab_info = RTW_GET_LE16(pframe + sizeof(struct ieee80211_hdr_3addr)); + /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); */ + /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)+2)); */ + listen_interval = RTW_GET_LE16(pframe + sizeof(struct ieee80211_hdr_3addr)+2); + + left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); + pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); + + DBG_8723A("%s\n", __func__); + + /* check if this stat has been successfully authenticated/assocated */ + if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) + { + if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) + { + status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA; + goto asoc_class2_error; + } + else + { + pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + } + else + { + pstat->state &= (~WIFI_FW_AUTH_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + + pstat->capability = capab_info; + + /* now parse all ieee802_11 ie to point to elems */ + if (rtw_ieee802_11_parse_elems23a(pos, left, &elems, 1) == ParseFailed || + !elems.ssid) { + DBG_8723A("STA " MAC_FMT " sent invalid association request\n", + MAC_ARG(pstat->hwaddr)); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto OnAssocReq23aFail; + } + + /* now we should check all the fields... */ + /* checking SSID */ + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SSID_IE_, &ie_len, + pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); + if (p == NULL) + { + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (ie_len == 0) /* broadcast ssid, however it is not allowed in assocreq */ + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + else { + /* check if ssid match */ + if (memcmp((void *)(p+2), cur->Ssid.ssid, cur->Ssid.ssid_len)) + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + + if (ie_len != cur->Ssid.ssid_len) + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (WLAN_STATUS_SUCCESS != status) + goto OnAssocReq23aFail; + + /* check if the supported rate is ok */ + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); + if (p == NULL) { + DBG_8723A("Rx a sta assoc-req which supported rate is empty!\n"); + /* use our own rate set as statoin used */ + /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ + /* supportRateNum = AP_BSSRATE_LEN; */ + + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto OnAssocReq23aFail; + } else { + memcpy(supportRate, p+2, ie_len); + supportRateNum = ie_len; + + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _EXT_SUPPORTEDRATES_IE_, &ie_len, + pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); + if (p != NULL) { + + if (supportRateNum<= sizeof(supportRate)) + { + memcpy(supportRate+supportRateNum, p+2, ie_len); + supportRateNum += ie_len; + } + } + } + + /* todo: mask supportRate between AP & STA -> move to update raid */ + /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ + + /* update station supportRate */ + pstat->bssratelen = supportRateNum; + memcpy(pstat->bssrateset, supportRate, supportRateNum); + Update23aTblForSoftAP(pstat->bssrateset, pstat->bssratelen); + + /* check RSN/WPA/WPS */ + pstat->dot8021xalg = 0; + pstat->wpa_psk = 0; + pstat->wpa_group_cipher = 0; + pstat->wpa2_group_cipher = 0; + pstat->wpa_pairwise_cipher = 0; + pstat->wpa2_pairwise_cipher = 0; + memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); + if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { + + int group_cipher = 0, pairwise_cipher = 0; + + wpa_ie = elems.rsn_ie; + wpa_ie_len = elems.rsn_ie_len; + + if (rtw_parse_wpa2_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(1); + + pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; + pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; + + if (!pstat->wpa2_group_cipher) + status = WLAN_REASON_INVALID_GROUP_CIPHER; + + if (!pstat->wpa2_pairwise_cipher) + status = WLAN_REASON_INVALID_PAIRWISE_CIPHER; + } else { + status = WLAN_STATUS_INVALID_IE; + } + + } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { + + int group_cipher = 0, pairwise_cipher = 0; + + wpa_ie = elems.wpa_ie; + wpa_ie_len = elems.wpa_ie_len; + + if (rtw_parse_wpa_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(0); + + pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; + pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; + + if (!pstat->wpa_group_cipher) + status = WLAN_STATUS_INVALID_GROUP_CIPHER; + + if (!pstat->wpa_pairwise_cipher) + status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER; + + } else { + status = WLAN_STATUS_INVALID_IE; + } + + } else { + wpa_ie = NULL; + wpa_ie_len = 0; + } + + if (WLAN_STATUS_SUCCESS != status) + goto OnAssocReq23aFail; + + pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + if (wpa_ie == NULL) { + if (elems.wps_ie) { + DBG_8723A("STA included WPS IE in " + "(Re)Association Request - assume WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + } else { + DBG_8723A("STA did not include WPA/RSN IE " + "in (Re)Association Request - possible WPS " + "use\n"); + pstat->flags |= WLAN_STA_MAYBE_WPS; + } + + /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ + /* that the selected registrar of AP is _FLASE */ + if ((psecuritypriv->wpa_psk > 0) && + (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { + if (pmlmepriv->wps_beacon_ie) { + u8 selected_registrar = 0; + + rtw_get_wps_attr_content23a(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, + WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL); + + if (!selected_registrar) { + DBG_8723A("selected_registrar is false , or AP is not ready to do WPS\n"); + + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + + goto OnAssocReq23aFail; + } + } + } + } else { + int copy_len; + + if (psecuritypriv->wpa_psk == 0) { + DBG_8723A("STA " MAC_FMT ": WPA/RSN IE in association " + "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); + + status = WLAN_STATUS_INVALID_IE; + + goto OnAssocReq23aFail; + } + + if (elems.wps_ie) { + DBG_8723A("STA included WPS IE in " + "(Re)Association Request - WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + copy_len = 0; + } else { + copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2); + } + + if (copy_len>0) + memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); + + } + + /* check if there is WMM IE & support WWM-PS */ + pstat->flags &= ~WLAN_STA_WME; + pstat->qos_option = 0; + pstat->qos_info = 0; + pstat->has_legacy_ac = true; + pstat->uapsd_vo = 0; + pstat->uapsd_vi = 0; + pstat->uapsd_be = 0; + pstat->uapsd_bk = 0; + if (pmlmepriv->qospriv.qos_option) + { + p = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset; ie_len = 0; + for (;;) + { + p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset); + if (p != NULL) { + if (!memcmp(p+2, WMM_IE, 6)) { + + pstat->flags |= WLAN_STA_WME; + + pstat->qos_option = 1; + pstat->qos_info = *(p+8); + + pstat->max_sp_len = (pstat->qos_info>>5)&0x3; + + if ((pstat->qos_info&0xf) != 0xf) + pstat->has_legacy_ac = true; + else + pstat->has_legacy_ac = false; + + if (pstat->qos_info&0xf) + { + if (pstat->qos_info&BIT(0)) + pstat->uapsd_vo = BIT(0)|BIT(1); + else + pstat->uapsd_vo = 0; + + if (pstat->qos_info&BIT(1)) + pstat->uapsd_vi = BIT(0)|BIT(1); + else + pstat->uapsd_vi = 0; + + if (pstat->qos_info&BIT(2)) + pstat->uapsd_bk = BIT(0)|BIT(1); + else + pstat->uapsd_bk = 0; + + if (pstat->qos_info&BIT(3)) + pstat->uapsd_be = BIT(0)|BIT(1); + else + pstat->uapsd_be = 0; + + } + + break; + } + } + else { + break; + } + p = p + ie_len + 2; + } + } + + /* save HT capabilities in the sta object */ + memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); + if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) + { + pstat->flags |= WLAN_STA_HT; + + pstat->flags |= WLAN_STA_WME; + + memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); + + } else + pstat->flags &= ~WLAN_STA_HT; + + if ((pmlmepriv->htpriv.ht_option == false) && (pstat->flags&WLAN_STA_HT)) + { + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto OnAssocReq23aFail; + } + + if ((pstat->flags & WLAN_STA_HT) && + ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || + (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) + { + DBG_8723A("HT: " MAC_FMT " tried to " + "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); + + /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ + /* goto OnAssocReq23aFail; */ + } + + /* */ + pstat->flags |= WLAN_STA_NONERP; + for (i = 0; i < pstat->bssratelen; i++) { + if ((pstat->bssrateset[i] & 0x7f) > 22) { + pstat->flags &= ~WLAN_STA_NONERP; + break; + } + } + + if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + pstat->flags |= WLAN_STA_SHORT_PREAMBLE; + else + pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; + + if (status != WLAN_STATUS_SUCCESS) + goto OnAssocReq23aFail; + +#ifdef CONFIG_8723AU_P2P + pstat->is_p2p_device = false; + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, NULL, &p2pielen))) + { + pstat->is_p2p_device = true; + if ((p2p_status_code = (u8)process_assoc_req_p2p_ie23a(pwdinfo, pframe, pkt_len, pstat))>0) + { + pstat->p2p_status_code = p2p_status_code; + status = WLAN_STATUS_CAPS_UNSUPPORTED; + goto OnAssocReq23aFail; + } + } +#ifdef CONFIG_8723AU_P2P + if (rtw_get_wfd_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, wfd_ie, &wfd_ielen)) + { + u8 attr_content[ 10 ] = { 0x00 }; + u32 attr_contentlen = 0; + + DBG_8723A("[%s] WFD IE Found!!\n", __func__); + rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); + if (attr_contentlen) + { + pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); + } + } +#endif + } + pstat->p2p_status_code = p2p_status_code; +#endif /* CONFIG_8723AU_P2P */ + + /* TODO: identify_proprietary_vendor_ie(); */ + /* Realtek proprietary IE */ + /* identify if this is Broadcom sta */ + /* identify if this is ralink sta */ + /* Customer proprietary IE */ + + /* get a unique AID */ + if (pstat->aid > 0) { + DBG_8723A(" old AID %d\n", pstat->aid); + } else { + for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) + if (pstapriv->sta_aid[pstat->aid - 1] == NULL) + break; + + if (pstat->aid > NUM_STA) + pstat->aid = NUM_STA; + if (pstat->aid > pstapriv->max_num_sta) { + + pstat->aid = 0; + + DBG_8723A(" no room for more AIDs\n"); + + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + + goto OnAssocReq23aFail; + + } else { + pstapriv->sta_aid[pstat->aid - 1] = pstat; + DBG_8723A("allocate new AID = (%d)\n", pstat->aid); + } + } + + pstat->state &= (~WIFI_FW_ASSOC_STATE); + pstat->state |= WIFI_FW_ASSOC_SUCCESS; + + spin_lock_bh(&pstapriv->auth_list_lock); + if (!list_empty(&pstat->auth_list)) { + list_del_init(&pstat->auth_list); + pstapriv->auth_list_cnt--; + } + spin_unlock_bh(&pstapriv->auth_list_lock); + + spin_lock_bh(&pstapriv->asoc_list_lock); + if (list_empty(&pstat->asoc_list)) { + pstat->expire_to = pstapriv->expire_to; + list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); + pstapriv->asoc_list_cnt++; + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + /* now the station is qualified to join our BSS... */ + if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && + (WLAN_STATUS_SUCCESS == status)) { +#ifdef CONFIG_8723AU_AP_MODE + /* 1 bss_cap_update & sta_info_update23a */ + bss_cap_update_on_sta_join23a(padapter, pstat); + sta_info_update23a(padapter, pstat); + + /* issue assoc rsp before notify station join event. */ + if (ieee80211_is_assoc_req(frame_control)) + issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP); + + /* 2 - report to upper layer */ + DBG_8723A("indicate_sta_join_event to upper layer - hostapd\n"); + rtw_cfg80211_indicate_sta_assoc(padapter, pframe, pkt_len); + + /* 3-(1) report sta add event */ + report_add_sta_event23a(padapter, pstat->hwaddr, pstat->aid); +#endif + } + + return _SUCCESS; + +asoc_class2_error: + +#ifdef CONFIG_8723AU_AP_MODE + issue_deauth23a(padapter, hdr->addr2, status); +#endif + + return _FAIL; + +OnAssocReq23aFail: + +#ifdef CONFIG_8723AU_AP_MODE + pstat->aid = 0; + if (ieee80211_is_assoc_req(frame_control)) + issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP); +#endif + +#endif /* CONFIG_8723AU_AP_MODE */ + + return _FAIL; +} + +unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + uint i; + int res; + unsigned short status; + struct ndis_802_11_var_ies *pIE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint pkt_len = skb->len; + + DBG_8723A("%s\n", __func__); + + /* check A1 matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), + ieee80211_get_DA(hdr))) + return _SUCCESS; + + if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) + return _SUCCESS; + + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + return _SUCCESS; + + del_timer_sync(&pmlmeext->link_timer); + + /* status */ + if ((status = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 2))) > 0) + { + DBG_8723A("assoc reject, status code: %d\n", status); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + res = -4; + goto report_assoc_result; + } + + /* get capabilities */ + pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); + + /* set slot time */ + pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20; + + /* AID */ + res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 4))&0x3fff); + + /* following are moved to join event callback function */ + /* to handle HT, WMM, rate adaptive, update MAC reg */ + /* for not to handle the synchronous IO in the tasklet */ + for (i = (6 + sizeof(struct ieee80211_hdr_3addr)); i < pkt_len;) { + pIE = (struct ndis_802_11_var_ies *)(pframe + i); + + switch (pIE->ElementID) + { + case _VENDOR_SPECIFIC_IE_: + if (!memcmp(pIE->data, WMM_PARA_OUI23A, 6))/* WMM */ + WMM_param_handler23a(padapter, pIE); +#if defined(CONFIG_8723AU_P2P) + else if (!memcmp(pIE->data, WFD_OUI23A, 4)) { /* WFD */ + DBG_8723A("[%s] Found WFD IE\n", __func__); + WFD_info_handler(padapter, pIE); + } +#endif + break; + + case _HT_CAPABILITY_IE_: /* HT caps */ + HT_caps_handler23a(padapter, pIE); + break; + + case _HT_EXTRA_INFO_IE_: /* HT info */ + HT_info_handler23a(padapter, pIE); + break; + + case _ERPINFO_IE_: + ERP_IE_handler23a(padapter, pIE); + + default: + break; + } + + i += (pIE->Length + 2); + } + + pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + + /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ + UpdateBrateTbl23a(padapter, pmlmeinfo->network.SupportedRates); + +report_assoc_result: + pmlmepriv->assoc_rsp_len = 0; + if (res > 0) { + kfree(pmlmepriv->assoc_rsp); + pmlmepriv->assoc_rsp = kmalloc(pkt_len, GFP_ATOMIC); + if (pmlmepriv->assoc_rsp) { + memcpy(pmlmepriv->assoc_rsp, pframe, pkt_len); + pmlmepriv->assoc_rsp_len = pkt_len; + } + } else + kfree(pmlmepriv->assoc_rsp); + + report_join_res23a(padapter, res); + + return _SUCCESS; +} + +unsigned int OnDeAuth23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + unsigned short reason; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + /* check A3 */ + if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))) + return _SUCCESS; + +#ifdef CONFIG_8723AU_P2P + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { + mod_timer(&pwdinfo->reset_ch_sitesurvey, + jiffies + msecs_to_jiffies(10)); + } +#endif /* CONFIG_8723AU_P2P */ + + reason = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); + + DBG_8723A("%s Reason code(%d)\n", __func__, reason); + +#ifdef CONFIG_8723AU_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + DBG_8723A_LEVEL(_drv_always_, "ap recv deauth reason code(%d) " + "sta:%pM\n", reason, hdr->addr2); + + psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + if (psta) { + u8 updated = 0; + + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&psta->asoc_list)) { + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta23a(padapter, psta, + false, reason); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + associated_clients_update23a(padapter, updated); + } + + return _SUCCESS; + } + else +#endif + { + DBG_8723A_LEVEL(_drv_always_, "sta recv deauth reason code(%d) " + "sta:%pM\n", reason, hdr->addr3); + + receive_disconnect23a(padapter, hdr->addr3, reason); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + return _SUCCESS; +} + +unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + unsigned short reason; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + /* check A3 */ + if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))) + return _SUCCESS; + +#ifdef CONFIG_8723AU_P2P + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) + { + mod_timer(&pwdinfo->reset_ch_sitesurvey, + jiffies + msecs_to_jiffies(10)); + } +#endif /* CONFIG_8723AU_P2P */ + + reason = le16_to_cpu(*(unsigned short *) + (pframe + sizeof(struct ieee80211_hdr_3addr))); + + DBG_8723A("%s Reason code(%d)\n", __func__, reason); + +#ifdef CONFIG_8723AU_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason code(%d)" + " sta:%pM\n", reason, hdr->addr2); + + psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + if (psta) { + u8 updated = 0; + + spin_lock_bh(&pstapriv->asoc_list_lock); + if (!list_empty(&psta->asoc_list)) { + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta23a(padapter, psta, + false, reason); + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + associated_clients_update23a(padapter, updated); + } + + return _SUCCESS; + } + else +#endif + { + DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason " + "code(%d) sta:%pM\n", reason, hdr->addr3); + + receive_disconnect23a(padapter, hdr->addr3, reason); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + return _SUCCESS; +} + +unsigned int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + DBG_8723A("%s\n", __func__); + return _SUCCESS; +} + +unsigned int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + return _FAIL; +} + +unsigned int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + u8 *addr; + struct sta_info *psta = NULL; + struct recv_reorder_ctrl *preorder_ctrl; + unsigned char *frame_body; + unsigned char category, action; + unsigned short tid, status, reason_code = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* check RA matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) + return _SUCCESS; + + DBG_8723A("%s\n", __func__); + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) + return _SUCCESS; + + addr = hdr->addr2; + psta = rtw_get_stainfo23a(pstapriv, addr); + + if (!psta) + return _SUCCESS; + + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); + + category = frame_body[0]; + if (category == WLAN_CATEGORY_BACK) { /* representing Block Ack */ + if (!pmlmeinfo->HT_enable) + return _SUCCESS; + action = frame_body[1]; + DBG_8723A("%s, action =%d\n", __func__, action); + switch (action) { + case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ + memcpy(&pmlmeinfo->ADDBA_req, &frame_body[2], + sizeof(struct ADDBA_request)); + process_addba_req23a(padapter, + (u8 *)&pmlmeinfo->ADDBA_req, addr); + if (pmlmeinfo->bAcceptAddbaReq == true) + issue_action_BA23a(padapter, addr, + WLAN_ACTION_ADDBA_RESP, 0); + else { + /* reject ADDBA Req */ + issue_action_BA23a(padapter, addr, + WLAN_ACTION_ADDBA_RESP, 37); + } + break; + case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ + status = RTW_GET_LE16(&frame_body[3]); + tid = ((frame_body[5] >> 2) & 0x7); + if (status == 0) { /* successful */ + DBG_8723A("agg_enable for TID =%d\n", tid); + psta->htpriv.agg_enable_bitmap |= 1 << tid; + psta->htpriv.candidate_tid_bitmap &= + ~CHKBIT(tid); + } else + psta->htpriv.agg_enable_bitmap &= ~CHKBIT(tid); + break; + + case WLAN_ACTION_DELBA: /* DELBA */ + if ((frame_body[3] & BIT(3)) == 0) { + psta->htpriv.agg_enable_bitmap &= + ~(1 << ((frame_body[3] >> 4) & 0xf)); + psta->htpriv.candidate_tid_bitmap &= + ~(1 << ((frame_body[3] >> 4) & 0xf)); + + /* reason_code = frame_body[4] | (frame_body[5] << 8); */ + reason_code = RTW_GET_LE16(&frame_body[4]); + } else if ((frame_body[3] & BIT(3)) == BIT(3)) { + tid = (frame_body[3] >> 4) & 0x0F; + + preorder_ctrl = &psta->recvreorder_ctrl[tid]; + preorder_ctrl->enable = false; + preorder_ctrl->indicate_seq = 0xffff; + } + + DBG_8723A("%s(): DELBA: %x(%x)\n", __func__, + pmlmeinfo->agg_enable_bitmap, reason_code); + /* todo: how to notify the host while receiving + DELETE BA */ + break; + default: + break; + } + } + return _SUCCESS; +} + +#ifdef CONFIG_8723AU_P2P + +static int get_reg_classes_full_count(struct p2p_channels channel_list) { + int cnt = 0; + int i; + + for (i = 0; i < channel_list.reg_classes; i++) + cnt += channel_list.reg_class[i].channels; + + return cnt; +} + +void issue_p2p_GO_request23a(struct rtw_adapter *padapter, u8* raddr) +{ + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_REQ; + u8 wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 }; + u8 wpsielen = 0, p2pielen = 0; + u16 len_channellist_attr = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + DBG_8723A("[%s] In\n", __func__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pwdinfo->negotiation_dialog_token = 1; /*Initialize the dialog value*/ + pframe = rtw_set_fixed_ie23a(pframe, 1, + &pwdinfo->negotiation_dialog_token, + &pattrib->pktlen); + + /* WPS Section */ + wpsielen = 0; + /* WPS OUI */ + *(u32*) (wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Device Password ID */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + + if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) + { + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); + } + else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN) + { + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + } + else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) + { + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); + } + + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110306 */ + /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Group Owner Intent */ + /* 3. Configuration Timeout */ + /* 4. Listen Channel */ + /* 5. Extended Listen Timing */ + /* 6. Intended P2P Interface Address */ + /* 7. Channel List */ + /* 8. P2P Device Info */ + /* 9. Operating Channel */ + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; + } + else + { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + } + + /* Group Owner Intent */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + /* Todo the tie breaker bit. */ + p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + /* Listen Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */ + + /* Extended Listen Timing ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Intended P2P Interface Address */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) + + get_reg_classes_full_count(pmlmeext->channel_list); + + *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } + } + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + + *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, + pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->operating_channel <= 14) + { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } + else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) + { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } + else + { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static void issue_p2p_GO_response(struct rtw_adapter *padapter, u8* raddr, u8* frame_body, uint len, u8 result) +{ + + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_RESP; + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u8 p2pielen = 0; + uint wpsielen = 0; + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; + u16 len_channellist_attr = 0; + int i, j; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + DBG_8723A("[%s] In, result = %d\n", __func__, result); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + /* The Dialog Token of provisioning discovery request frame. */ + pwdinfo->negotiation_dialog_token = frame_body[7]; + pframe = rtw_set_fixed_ie23a(pframe, 1, + &pwdinfo->negotiation_dialog_token, + &pattrib->pktlen); + + /* Commented by Albert 20110328 */ + /* Try to get the device password ID from the WPS IE of group + negotiation request frame */ + /* WiFi Direct test plan 5.1.15 */ + rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); + rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, + (u8 *)&wps_devicepassword_id, + &wps_devicepassword_id_len); + wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); + + memset(wpsie, 0x00, 255); + wpsielen = 0; + + /* WPS Section */ + wpsielen = 0; + /* WPS OUI */ + *(u32*) (wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Device Password ID */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) { + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) { + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); + } else { + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); + } + wpsielen += 2; + + /* Commented by Kurt 20120113 */ + /* If some device wants to do p2p handshake without sending prov_disc_req */ + /* We have to get peer_req_cm from here. */ + if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); + } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); + } else { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); + } + } + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, + (unsigned char *) wpsie, &pattrib->pktlen); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20100908 */ + /* According to the P2P Specification, the group negoitation + response frame should contain 9 P2P attributes */ + /* 1. Status */ + /* 2. P2P Capability */ + /* 3. Group Owner Intent */ + /* 4. Configuration Timeout */ + /* 5. Operating Channel */ + /* 6. Intended P2P Interface Address */ + /* 7. Channel List */ + /* 8. Device Info */ + /* 9. Group ID (Only GO) */ + + /* ToDo: */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = result; + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + /* Commented by Albert 2011/03/08 */ + /* According to the P2P specification */ + /* if the sending device will be client, the P2P + Capability should be reserved of group negotation + response frame */ + p2pie[p2pielen++] = 0; + } else { + /* Be group owner or meet the error case */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + } + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | + P2P_GRPCAP_PERSISTENT_GROUP; + } else { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + } + + /* Group Owner Intent */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + if (pwdinfo->peer_intent & 0x01) { + /* Peer's tie breaker bit is 1, our tie breaker + bit should be 0 */ + p2pie[p2pielen++] = (pwdinfo->intent << 1); + } else { + /* Peer's tie breaker bit is 0, our tie breaker bit + should be 1 */ + p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); + } + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; + /* 2 seconds needed to be the P2P Client */ + p2pie[p2pielen++] = 200; + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && + (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + /* operating channel number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; + + /* Intended P2P Interface Address */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Country String(3) */ + /* + (Operating Class (1) + Number of Channels(1)) * + Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + + *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; + i < pmlmeext->channel_list.reg_class[j].channels; i++) { + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].channel[i]; + } + } + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field + (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + + *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, + pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + /* Group ID Attribute */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); + p2pielen += 2; + + /* Value: */ + /* p2P Device Address */ + memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, + pwdinfo->nego_ssidlen); + p2pielen += pwdinfo->nego_ssidlen; + + } + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static void issue_p2p_GO_confirm(struct rtw_adapter *padapter, u8* raddr, + u8 result) +{ + + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_CONF; + u8 p2pie[ 255 ] = { 0x00 }; + u8 p2pielen = 0; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + DBG_8723A("[%s] In\n", __func__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, + &pwdinfo->negotiation_dialog_token, + &pattrib->pktlen); + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110306 */ + /* According to the P2P Specification, the group negoitation + request frame should contain 5 P2P attributes */ + /* 1. Status */ + /* 2. P2P Capability */ + /* 3. Operating Channel */ + /* 4. Channel List */ + /* 5. Group ID (if this WiFi is GO) */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = result; + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | + P2P_GRPCAP_PERSISTENT_GROUP; + } else { + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + } + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + if (pwdinfo->peer_operating_ch <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->peer_operating_ch >= 36) && + (pwdinfo->peer_operating_ch <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + p2pie[p2pielen++] = pwdinfo->peer_operating_ch; + } else { + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } + else if ((pwdinfo->operating_channel >= 36) && + (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + /* Use the listen channel as the operating channel */ + p2pie[p2pielen++] = pwdinfo->operating_channel; + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_le16(pwdinfo->channel_list_attr_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, + pwdinfo->channel_list_attr_len); + p2pielen += pwdinfo->channel_list_attr_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Group ID Attribute */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); + p2pielen += 2; + + /* Value: */ + /* p2P Device Address */ + memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, + pwdinfo->nego_ssidlen); + p2pielen += pwdinfo->nego_ssidlen; + } + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *)p2pie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +void issue_p2p_invitation_request23a(struct rtw_adapter *padapter, u8* raddr) +{ + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_INVIT_REQ; + u8 p2pie[ 255 ] = { 0x00 }; + u8 p2pielen = 0; + u8 dialogToken = 3; + u16 len_channellist_attr = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + int i, j; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, raddr); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101011 */ + /* According to the P2P Specification, the P2P Invitation + request frame should contain 7 P2P attributes */ + /* 1. Configuration Timeout */ + /* 2. Invitation Flags */ + /* 3. Operating Channel (Only GO) */ + /* 4. P2P Group BSSID (Should be included if I am the GO) */ + /* 5. Channel List */ + /* 6. P2P Group ID */ + /* 7. P2P Device Info */ + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; + /* 2 seconds needed to be the P2P Client */ + p2pie[p2pielen++] = 200; + + /* Invitation Flags */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT; + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->invitereq_info.operating_ch <= 14) + p2pie[p2pielen++] = 0x51; + else if ((pwdinfo->invitereq_info.operating_ch >= 36) && + (pwdinfo->invitereq_info.operating_ch <= 48)) + p2pie[p2pielen++] = 0x73; + else + p2pie[p2pielen++] = 0x7c; + + /* Channel Number */ + /* operating channel number */ + p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; + + if (ether_addr_equal(myid(&padapter->eeprompriv), + pwdinfo->invitereq_info.go_bssid)) { + /* P2P Group BSSID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, + ETH_ALEN); + p2pielen += ETH_ALEN; + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + (Operating Class (1) + Number of Channels(1)) * + Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + + *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; + i < pmlmeext->channel_list.reg_class[j].channels; i++) { + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].channel[i]; + } + } + + /* P2P Group ID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, + pwdinfo->invitereq_info.ssidlen); + p2pielen += pwdinfo->invitereq_info.ssidlen; + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field + (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, + pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +void issue_p2p_invitation_response23a(struct rtw_adapter *padapter, u8 *raddr, + u8 dialogToken, u8 status_code) +{ + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_INVIT_RESP; + u8 p2pie[ 255 ] = { 0x00 }; + u8 p2pielen = 0; + u16 len_channellist_attr = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + int i, j; + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, raddr); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101005 */ + /* According to the P2P Specification, the P2P Invitation + response frame should contain 5 P2P attributes */ + /* 1. Status */ + /* 2. Configuration Timeout */ + /* 3. Operating Channel (Only GO) */ + /* 4. P2P Group BSSID (Only GO) */ + /* 5. Channel List */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */ + /* Sent the event receiving the P2P Invitation Req frame + to DMP UI. */ + /* DMP had to compare the MAC address to find out the profile. */ + /* So, the WiFi driver will send the + P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */ + /* If the UI found the corresponding profile, the WiFi driver + sends the P2P Invitation Req */ + /* to NB to rebuild the persistent group. */ + p2pie[p2pielen++] = status_code; + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; + /* 2 seconds needed to be the P2P Client */ + p2pie[p2pielen++] = 200; + + if (status_code == P2P_STATUS_SUCCESS) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* The P2P Invitation request frame asks this + Wi-Fi device to be the P2P GO */ + /* In this case, the P2P Invitation response + frame should carry the two more P2P attributes. */ + /* First one is operating channel attribute. */ + /* Second one is P2P Group BSSID attribute. */ + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" + section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + /* Copy from SD7 */ + p2pie[p2pielen++] = 0x51; + + /* Channel Number */ + /* operating channel number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; + + /* P2P Group BSSID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), + ETH_ALEN); + p2pielen += ETH_ALEN; + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + (Operating Class (1) + Number of Channels(1)) * + Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + + *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = + pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; + i < pmlmeext->channel_list.reg_class[j].channels; + i++) { + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } + } + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *)p2pie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +void issue_p2p_provision_request23a(struct rtw_adapter *padapter, u8 *pssid, + u8 ussidlen, u8 *pdev_raddr) +{ + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = 1; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_REQ; + u8 wpsie[100] = { 0x00 }; + u8 wpsielen = 0; + u32 p2pielen = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + DBG_8723A("[%s] In\n", __func__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, pdev_raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, pdev_raddr); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + p2pielen = build_prov_disc_request_p2p_ie23a(pwdinfo, pframe, pssid, + ussidlen, pdev_raddr); + + pframe += p2pielen; + pattrib->pktlen += p2pielen; + + wpsielen = 0; + /* WPS OUI */ + *(u32*) (wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Config Method */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, + (unsigned char *) wpsie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static u8 is_matched_in_profilelist(u8 *peermacaddr, + struct profile_info *profileinfo) +{ + u8 i, match_result = 0; + + DBG_8723A("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, + peermacaddr[0], peermacaddr[1], peermacaddr[2], + peermacaddr[3], peermacaddr[4], peermacaddr[5]); + + for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) { + DBG_8723A("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X " + "%.2X\n", __func__, profileinfo->peermac[0], + profileinfo->peermac[1], profileinfo->peermac[2], + profileinfo->peermac[3], profileinfo->peermac[4], + profileinfo->peermac[5]); + if (ether_addr_equal(peermacaddr, profileinfo->peermac)) { + match_result = 1; + DBG_8723A("[%s] Match!\n", __func__); + break; + } + } + + return match_result; +} + +void issue_probersp23a_p2p23a(struct rtw_adapter *padapter, unsigned char *da) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u16 beacon_interval = 100; + u16 capInfo = 0; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 wpsie[255] = { 0x00 }; + u32 wpsielen = 0, p2pielen = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = + &padapter->cfg80211_wdinfo; + struct ieee80211_channel *ieee_ch = + &pcfg80211_wdinfo->remain_on_ch_channel; + u8 listen_channel = + (u8)ieee80211_frequency_to_channel(ieee_ch->center_freq); + + /* DBG_8723A("%s\n", __func__); */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + mac = myid(&padapter->eeprompriv); + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr2, mac); + + /* Use the device address for BSSID field. */ + ether_addr_copy(pwlanhdr->addr3, mac); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(fctrl, WIFI_PROBERSP); + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = pattrib->hdrlen; + pframe += pattrib->hdrlen; + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + memcpy(pframe, (unsigned char *) &beacon_interval, 2); + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of + WiFi Direct Spec) */ + capInfo |= cap_ShortPremble; + capInfo |= cap_ShortSlot; + + memcpy(pframe, (unsigned char *) &capInfo, 2); + pframe += 2; + pattrib->pktlen += 2; + + /* SSID */ + pframe = rtw_set_ie23a(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, + &pattrib->pktlen); + + /* supported rates... */ + /* Use the OFDM rate in the P2P probe response frame. + (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pwdinfo->support_rate, &pattrib->pktlen); + + /* DS parameter set */ + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled && + listen_channel != 0) { + pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + &listen_channel, &pattrib->pktlen); + } else { + pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + &pwdinfo->listen_channel, + &pattrib->pktlen); + } + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + if (pmlmepriv->wps_probe_resp_ie && + pmlmepriv->p2p_probe_resp_ie) { + /* WPS IE */ + memcpy(pframe, pmlmepriv->wps_probe_resp_ie, + pmlmepriv->wps_probe_resp_ie_len); + pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len; + pframe += pmlmepriv->wps_probe_resp_ie_len; + + /* P2P IE */ + memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, + pmlmepriv->p2p_probe_resp_ie_len); + pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len; + pframe += pmlmepriv->p2p_probe_resp_ie_len; + } + } else { + + /* Todo: WPS IE */ + /* Noted by Albert 20100907 */ + /* According to the WPS specification, all the WPS + attribute is presented by Big Endian. */ + + wpsielen = 0; + /* WPS OUI */ + *(u32*) (wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* WiFi Simple Config State */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; + + /* Response Type */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; + + /* UUID-E */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); + wpsielen += 0x10; + + /* Manufacturer */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0007); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, "Realtek", 7); + wpsielen += 7; + + /* Model Name */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0006); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, "8192CU", 6); + wpsielen += 6; + + /* Model Number */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[ wpsielen++ ] = 0x31; /* character 1 */ + + /* Serial Number */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, "123456", ETH_ALEN); + wpsielen += ETH_ALEN; + + /* Primary Device Type */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + wpsielen += 2; + + /* OUI */ + *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* Sub Category ID */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + wpsielen += 2; + + /* Device Name */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(pwdinfo->device_name_len); + wpsielen += 2; + + /* Value: */ + if (pwdinfo->device_name_len) { + memcpy(wpsie + wpsielen, pwdinfo->device_name, + pwdinfo->device_name_len); + wpsielen += pwdinfo->device_name_len; + } + + /* Config Method */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(pwdinfo->supported_wps_cm); + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, + (unsigned char *)wpsie, + &pattrib->pktlen); + + p2pielen = build_probe_resp_p2p_ie23a(pwdinfo, pframe); + pframe += p2pielen; + pattrib->pktlen += p2pielen; + } + +#ifdef CONFIG_8723AU_P2P + if (pwdinfo->wfd_info->wfd_enable) { + wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } else if (pmlmepriv->wfd_probe_resp_ie && + pmlmepriv->wfd_probe_resp_ie_len > 0) { + /* WFD IE */ + memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, + pmlmepriv->wfd_probe_resp_ie_len); + pattrib->pktlen += pmlmepriv->wfd_probe_resp_ie_len; + pframe += pmlmepriv->wfd_probe_resp_ie_len; + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static int _issue23a_probereq_p2p(struct rtw_adapter *padapter, u8 *da, + int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 wpsie[255] = {0x00}, p2pie[255] = {0x00}; + u16 wpsielen = 0, p2pielen = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + mac = myid(&padapter->eeprompriv); + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + if (da) { + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr3, da); + } else { + if ((pwdinfo->p2p_info.scan_op_ch_only) || + (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { + /* This two flags will be set when this is + only the P2P client mode. */ + ether_addr_copy(pwlanhdr->addr1, + pwdinfo->p2p_peer_interface_addr); + ether_addr_copy(pwlanhdr->addr3, + pwdinfo->p2p_peer_interface_addr); + } else { + /* broadcast probe request frame */ + ether_addr_copy(pwlanhdr->addr1, bc_addr); + ether_addr_copy(pwlanhdr->addr3, bc_addr); + } + } + ether_addr_copy(pwlanhdr->addr2, mac); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_PROBEREQ); + + pframe += sizeof (struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { + pframe = rtw_set_ie23a(pframe, _SSID_IE_, + pwdinfo->tx_prov_disc_info.ssid.ssid_len, + pwdinfo->tx_prov_disc_info.ssid.ssid, + &pattrib->pktlen); + } else { + pframe = rtw_set_ie23a(pframe, _SSID_IE_, + P2P_WILDCARD_SSID_LEN, + pwdinfo->p2p_wildcard_ssid, + &pattrib->pktlen); + } + /* Use the OFDM rate in the P2P probe request frame. + (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */ + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pwdinfo->support_rate, &pattrib->pktlen); + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + if (pmlmepriv->wps_probe_req_ie && + pmlmepriv->p2p_probe_req_ie) { + /* WPS IE */ + memcpy(pframe, pmlmepriv->wps_probe_req_ie, + pmlmepriv->wps_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + pframe += pmlmepriv->wps_probe_req_ie_len; + + /* P2P IE */ + memcpy(pframe, pmlmepriv->p2p_probe_req_ie, + pmlmepriv->p2p_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len; + pframe += pmlmepriv->p2p_probe_req_ie_len; + } + } else { + + /* WPS IE */ + /* Noted by Albert 20110221 */ + /* According to the WPS specification, all the WPS + attribute is presented by Big Endian. */ + + wpsielen = 0; + /* WPS OUI */ + *(u32*) (wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + if (pmlmepriv->wps_probe_req_ie == NULL) { + /* UUID-E */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_UUID_E); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), + ETH_ALEN); + wpsielen += 0x10; + + /* Config Method */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(pwdinfo->supported_wps_cm); + wpsielen += 2; + } + + /* Device Name */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(pwdinfo->device_name_len); + wpsielen += 2; + + /* Value: */ + memcpy(wpsie + wpsielen, pwdinfo->device_name, + pwdinfo->device_name_len); + wpsielen += pwdinfo->device_name_len; + + /* Primary Device Type */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI); + wpsielen += 2; + + /* OUI */ + *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* Sub Category ID */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP); + wpsielen += 2; + + /* Device Password ID */ + /* Type: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + /* Registrar-specified */ + *(u16*) (wpsie + wpsielen) = + cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, + (unsigned char *)wpsie, + &pattrib->pktlen); + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110221 */ + /* According to the P2P Specification, the probe request + frame should contain 5 P2P attributes */ + /* 1. P2P Capability */ + /* 2. P2P Device ID if this probe request wants to + find the specific P2P device */ + /* 3. Listen Channel */ + /* 4. Extended Listen Timing */ + /* 5. Operating Channel if this WiFi is working as + the group owner now */ + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | + DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + + /* Listen Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + /* listen channel */ + p2pie[p2pielen++] = pwdinfo->listen_channel; + + /* Extended Listen Timing */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Operating Channel (if this WiFi is working as + the group owner now) */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" + section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + /* operating channel number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; + } + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *)p2pie, + &pattrib->pktlen); + + if (pmlmepriv->wps_probe_req_ie) { + /* WPS IE */ + memcpy(pframe, pmlmepriv->wps_probe_req_ie, + pmlmepriv->wps_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + pframe += pmlmepriv->wps_probe_req_ie_len; + } + } + +#ifdef CONFIG_8723AU_P2P + if (pwdinfo->wfd_info->wfd_enable) { + wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } else if (pmlmepriv->wfd_probe_req_ie && + pmlmepriv->wfd_probe_req_ie_len>0) { + /* WFD IE */ + memcpy(pframe, pmlmepriv->wfd_probe_req_ie, + pmlmepriv->wfd_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->wfd_probe_req_ie_len; + pframe += pmlmepriv->wfd_probe_req_ie_len; + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz)); + + if (wait_ack) { + ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); + } else { + dump_mgntframe23a(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +inline void issue23a_probereq_p2p(struct rtw_adapter *adapter, u8 *da) +{ + _issue23a_probereq_p2p(adapter, da, false); +} + +int issue23a_probereq_p2p_ex(struct rtw_adapter *adapter, u8 *da, + int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + unsigned long start = jiffies; + + do { + ret = _issue23a_probereq_p2p(adapter, da, + wait_ms > 0 ? true : false); + + i++; + + if (adapter->bDriverStopped || adapter->bSurpriseRemoved) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } + + if (try_cnt && wait_ms) { + if (da) + DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " + "in %u ms\n", FUNC_ADPT_ARG(adapter), + MAC_ARG(da), rtw_get_oper_ch23a(adapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + else + DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(adapter), + rtw_get_oper_ch23a(adapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + } +exit: + return ret; +} + +#endif /* CONFIG_8723AU_P2P */ + +static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) +{ + struct rtw_adapter *adapter = recv_frame->adapter; + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct sk_buff *skb = recv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 seq_ctrl; + + seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | + (recv_frame->attrib.frag_num & 0xf); + + if (ieee80211_has_retry(hdr->frame_control)) { + if (token >= 0) { + if ((seq_ctrl == mlmeext->action_public_rxseq) && + (token == mlmeext->action_public_dialog_token)) { + DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " + "rxseq = 0x%x, token:%d\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, + mlmeext->action_public_rxseq, token); + return _FAIL; + } + } else { + if (seq_ctrl == mlmeext->action_public_rxseq) { + DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, " + "rxseq = 0x%x\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, + mlmeext->action_public_rxseq); + return _FAIL; + } + } + } + + mlmeext->action_public_rxseq = seq_ctrl; + + if (token >= 0) + mlmeext->action_public_dialog_token = token; + + return _SUCCESS; +} + +static unsigned int on_action_public23a_p2p(struct recv_frame *precv_frame) +{ + struct rtw_adapter *padapter = precv_frame->adapter; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint len = skb->len; + u8 *frame_body; + u8 dialogToken = 0; +#ifdef CONFIG_8723AU_P2P + u8 *p2p_ie; + u32 p2p_ielen; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 result = P2P_STATUS_SUCCESS; +#endif /* CONFIG_8723AU_P2P */ + + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); + + dialogToken = frame_body[7]; + + if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) + return _FAIL; + +#ifdef CONFIG_8723AU_P2P + del_timer_sync(&pwdinfo->reset_ch_sitesurvey); + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + rtw_cfg80211_rx_p2p_action_public(padapter, pframe, len); + } else { + /* Do nothing if the driver doesn't enable the P2P function. */ + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) + return _SUCCESS; + + len -= sizeof(struct ieee80211_hdr_3addr); + + switch (frame_body[ 6 ])/* OUI Subtype */ + { + case P2P_GO_NEGO_REQ: + DBG_8723A("[%s] Got GO Nego Req Frame\n", __func__); + memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) + { + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + } + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) + { + /* Commented by Albert 20110526 */ + /* In this case, this means the previous nego fail doesn't be reset yet. */ + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + /* Restore the previous p2p state */ + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + DBG_8723A("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo)); + } + + /* Commented by Kurt 20110902 */ + /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); + + /* Commented by Kurt 20120113 */ + /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */ + if (is_zero_ether_addr(pwdinfo->rx_prov_disc_info.peerDevAddr)) + ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2); + + result = process_p2p_group_negotation_req23a(pwdinfo, frame_body, len); + issue_p2p_GO_response(padapter, hdr->addr2, + frame_body, len, result); + + /* Commented by Albert 20110718 */ + /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */ + mod_timer(&pwdinfo->restore_p2p_state_timer, + jiffies + msecs_to_jiffies(5000)); + break; + + case P2P_GO_NEGO_RESP: + DBG_8723A("[%s] Got GO Nego Resp Frame\n", __func__); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) + { + /* Commented by Albert 20110425 */ + /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */ + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + pwdinfo->nego_req_info.benable = false; + result = process_p2p_group_negotation_resp23a(pwdinfo, frame_body, len); + issue_p2p_GO_confirm(pwdinfo->padapter, + hdr->addr2, + result); + if (result == P2P_STATUS_SUCCESS) { + if (rtw_p2p_role(pwdinfo) == + P2P_ROLE_CLIENT) { + pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; + pwdinfo->p2p_info.scan_op_ch_only = 1; + mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); + } + } + + /* Reset the dialog token for group negotiation frames. */ + pwdinfo->negotiation_dialog_token = 1; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) + { + mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000)); + } + } else { + DBG_8723A("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__); + } + + break; + + case P2P_GO_NEGO_CONF: + + DBG_8723A("[%s] Got GO Nego Confirm Frame\n", __func__); + result = process_p2p_group_negotation_confirm23a(pwdinfo, frame_body, len); + if (P2P_STATUS_SUCCESS == result) + { + if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) + { + pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch; + pwdinfo->p2p_info.scan_op_ch_only = 1; + mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); + } + } + break; + + case P2P_INVIT_REQ: + /* Added by Albert 2010/10/05 */ + /* Received the P2P Invite Request frame. */ + + DBG_8723A("[%s] Got invite request frame!\n", __func__); + if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen))) + { + /* Parse the necessary information from the P2P Invitation Request frame. */ + /* For example: The MAC address of sending this P2P Invitation Request frame. */ + u32 attr_contentlen = 0; + u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + struct group_id_info group_id; + u8 invitation_flag = 0; + + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); + if (attr_contentlen) + { + + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); + /* Commented by Albert 20120510 */ + /* Copy to the pwdinfo->p2p_peer_interface_addr. */ + /* So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */ + /* #> iwpriv wlan0 p2p_get peer_ifa */ + /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */ + + if (attr_contentlen) + { + DBG_8723A("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, + pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], + pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], + pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); + } + + if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) + { + /* Re-invoke the persistent group. */ + + memset(&group_id, 0x00, sizeof(struct group_id_info)); + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen); + if (attr_contentlen) { + if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) { + /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + status_code = P2P_STATUS_SUCCESS; + } + else + { + /* The p2p device sending this p2p invitation request wants to be the persistent GO. */ + if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[ 0 ])) + { + u8 operatingch_info[5] = { 0x00 }; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + { + if (rtw_ch_set_search_ch23a(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) + { + /* The operating channel is acceptable for this device. */ + pwdinfo->rx_invitereq_info.operation_ch[0]= operatingch_info[4]; + pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; + mod_timer(&pwdinfo->reset_ch_sitesurvey, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH)); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + status_code = P2P_STATUS_SUCCESS; + } + else + { + /* The operating channel isn't supported by this device. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + status_code = P2P_STATUS_FAIL_NO_COMMON_CH; + mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(3000)); + } + } + else { + /* Commented by Albert 20121130 */ + /* Intel will use the different P2P IE to store the operating channel information */ + /* Workaround for Intel WiDi 3.5 */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + status_code = P2P_STATUS_SUCCESS; + } + } + else + { + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); + + status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; + } + } + } + else + { + DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + } + else + { + /* Received the invitation to join a P2P group. */ + + memset(&group_id, 0x00, sizeof(struct group_id_info)); + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen); + if (attr_contentlen) + { + if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) { + /* In this case, the GO can't be myself. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + else + { + /* The p2p device sending this p2p invitation request wants to join an existing P2P group */ + /* Commented by Albert 2012/06/28 */ + /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */ + /* The peer device address should be the destination address for the provisioning discovery request. */ + /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */ + /* The peer interface address should be the address for WPS mac address */ + ether_addr_copy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN); + status_code = P2P_STATUS_SUCCESS; + } + } + else + { + DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + } + } + else + { + DBG_8723A("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + + DBG_8723A("[%s] status_code = %d\n", __func__, status_code); + + pwdinfo->inviteresp_info.token = frame_body[ 7 ]; + issue_p2p_invitation_response23a(padapter, hdr->addr2, pwdinfo->inviteresp_info.token, status_code); + } + break; + + case P2P_INVIT_RESP: + { + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + + DBG_8723A("[%s] Got invite response frame!\n", __func__); + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen))) + { + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + + if (attr_contentlen == 1) + { + DBG_8723A("[%s] Status = %d\n", __func__, attr_content); + pwdinfo->invitereq_info.benable = false; + + if (attr_content == P2P_STATUS_SUCCESS) + { + if (ether_addr_equal(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv))) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) { + mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000)); + } + break; + } + case P2P_DEVDISC_REQ: + + process_p2p_devdisc_req23a(pwdinfo, pframe, len); + + break; + + case P2P_DEVDISC_RESP: + + process_p2p_devdisc_resp23a(pwdinfo, pframe, len); + + break; + + case P2P_PROVISION_DISC_REQ: + DBG_8723A("[%s] Got Provisioning Discovery Request Frame\n", __func__); + process_p2p_provdisc_req23a(pwdinfo, pframe, len); + ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2); + + /* 20110902 Kurt */ + /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); + + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); + mod_timer(&pwdinfo->restore_p2p_state_timer, + jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT)); + break; + + case P2P_PROVISION_DISC_RESP: + /* Commented by Albert 20110707 */ + /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */ + DBG_8723A("[%s] Got Provisioning Discovery Response Frame\n", __func__); + /* Commented by Albert 20110426 */ + /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */ + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); + process_p2p_provdisc_resp23a(pwdinfo, pframe); + mod_timer(&pwdinfo->restore_p2p_state_timer, + jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT)); + break; + + } + } +#endif /* CONFIG_8723AU_P2P */ + + return _SUCCESS; +} + +static unsigned int on_action_public23a_vendor(struct recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); + + if (!memcmp(frame_body + 2, P2P_OUI23A, 4)) { + ret = on_action_public23a_p2p(precv_frame); + } + + return ret; +} + +static unsigned int +on_action_public23a_default(struct recv_frame *precv_frame, u8 action) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + uint frame_len = skb->len; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); + u8 token; + struct rtw_adapter *adapter = precv_frame->adapter; + int cnt = 0; + char msg[64]; + + token = frame_body[2]; + + if (rtw_action_public_decache(precv_frame, token) == _FAIL) + goto exit; + + cnt += sprintf((msg+cnt), "%s(token:%u)", + action_public_str23a(action), token); + rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg); + + ret = _SUCCESS; + +exit: + return ret; +} + +unsigned int on_action_public23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr); + u8 category, action; + + /* check RA matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) + goto exit; + + category = frame_body[0]; + if (category != WLAN_CATEGORY_PUBLIC) + goto exit; + + action = frame_body[1]; + switch (action) { + case ACT_PUBLIC_VENDOR: + ret = on_action_public23a_vendor(precv_frame); + break; + default: + ret = on_action_public23a_default(precv_frame, action); + break; + } + +exit: + return ret; +} + +unsigned int OnAction23a_ht(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction23a_wmm(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction23a_p2p(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_P2P + u8 *frame_body; + u8 category, OUI_Subtype, dialogToken = 0; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + uint len = skb->len; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + DBG_8723A("%s\n", __func__); + + /* check RA matches or not */ + if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1)) + return _SUCCESS; + + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); + + category = frame_body[0]; + if (category != WLAN_CATEGORY_VENDOR_SPECIFIC) + return _SUCCESS; + + if (cpu_to_be32(*((u32*) (frame_body + 1))) != P2POUI) + return _SUCCESS; + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + rtw_cfg80211_rx_action_p2p(padapter, pframe, len); + return _SUCCESS; + } else { + len -= sizeof(struct ieee80211_hdr_3addr); + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + + switch (OUI_Subtype) + { + case P2P_NOTICE_OF_ABSENCE: + break; + + case P2P_PRESENCE_REQUEST: + process_p2p_presence_req23a(pwdinfo, pframe, len); + break; + + case P2P_PRESENCE_RESPONSE: + break; + + case P2P_GO_DISC_REQUEST: + break; + + default: + break; + } + } +#endif /* CONFIG_8723AU_P2P */ + + return _SUCCESS; +} + +unsigned int OnAction23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + int i; + unsigned char category; + struct action_handler *ptable; + unsigned char *frame_body; + struct sk_buff *skb = precv_frame->pkt; + u8 *pframe = skb->data; + + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); + + category = frame_body[0]; + + for (i = 0; + i < sizeof(OnAction23a_tbl) / sizeof(struct action_handler); i++) { + ptable = &OnAction23a_tbl[i]; + + if (category == ptable->num) + ptable->func(padapter, precv_frame); + } + + return _SUCCESS; +} + +unsigned int DoReserved23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + return _SUCCESS; +} + +struct xmit_frame *alloc_mgtxmitframe23a(struct xmit_priv *pxmitpriv) +{ + struct xmit_frame *pmgntframe; + struct xmit_buf *pxmitbuf; + + pmgntframe = rtw_alloc_xmitframe23a_ext(pxmitpriv); + + if (!pmgntframe) { + DBG_8723A(FUNC_ADPT_FMT" alloc xmitframe fail\n", + FUNC_ADPT_ARG(pxmitpriv->adapter)); + goto exit; + } + + pxmitbuf = rtw_alloc_xmitbuf23a_ext(pxmitpriv); + if (!pxmitbuf) { + DBG_8723A(FUNC_ADPT_FMT" alloc xmitbuf fail\n", + FUNC_ADPT_ARG(pxmitpriv->adapter)); + rtw_free_xmitframe23a(pxmitpriv, pmgntframe); + pmgntframe = NULL; + goto exit; + } + + pmgntframe->frame_tag = MGNT_FRAMETAG; + pmgntframe->pxmitbuf = pxmitbuf; + pmgntframe->buf_addr = pxmitbuf->pbuf; + pxmitbuf->priv_data = pmgntframe; + +exit: + return pmgntframe; +} + +/**************************************************************************** + +Following are some TX fuctions for WiFi MLME + +*****************************************************************************/ + +void update_mgnt_tx_rate23a(struct rtw_adapter *padapter, u8 rate) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + pmlmeext->tx_rate = rate; + DBG_8723A("%s(): rate = %x\n", __func__, rate); +} + +void update_mgntframe_attrib23a(struct rtw_adapter *padapter, + struct pkt_attrib *pattrib) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + memset((u8 *)pattrib, 0, sizeof(struct pkt_attrib)); + + pattrib->hdrlen = 24; + pattrib->nr_frags = 1; + pattrib->priority = 7; + pattrib->mac_id = 0; + pattrib->qsel = 0x12; + + pattrib->pktlen = 0; + + if (pmlmeext->cur_wireless_mode & WIRELESS_11B) + pattrib->raid = 6;/* b mode */ + else + pattrib->raid = 5;/* a/g mode */ + + pattrib->encrypt = _NO_PRIVACY_; + pattrib->bswenc = false; + + pattrib->qos_en = false; + pattrib->ht_en = false; + pattrib->bwmode = HT_CHANNEL_WIDTH_20; + pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pattrib->sgi = false; + + pattrib->seqnum = pmlmeext->mgnt_seq; + + pattrib->retry_ctrl = true; +} + +void dump_mgntframe23a(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe) +{ + if (padapter->bSurpriseRemoved == true || + padapter->bDriverStopped == true) + return; + + rtw_hal_mgnt_xmit23a(padapter, pmgntframe); +} + +s32 dump_mgntframe23a_and_wait(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe, int timeout_ms) +{ + s32 ret = _FAIL; + unsigned long irqL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; + struct submit_ctx sctx; + + if (padapter->bSurpriseRemoved == true || + padapter->bDriverStopped == true) + return ret; + + rtw_sctx_init23a(&sctx, timeout_ms); + pxmitbuf->sctx = &sctx; + + ret = rtw_hal_mgnt_xmit23a(padapter, pmgntframe); + + if (ret == _SUCCESS) + ret = rtw_sctx_wait23a(&sctx); + + spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); + pxmitbuf->sctx = NULL; + spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL); + + return ret; +} + +s32 dump_mgntframe23a_and_wait_ack23a(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe) +{ + s32 ret = _FAIL; + u32 timeout_ms = 500;/* 500ms */ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter->bSurpriseRemoved == true || + padapter->bDriverStopped == true) + return -1; + + mutex_lock(&pxmitpriv->ack_tx_mutex); + pxmitpriv->ack_tx = true; + + pmgntframe->ack_report = 1; + if (rtw_hal_mgnt_xmit23a(padapter, pmgntframe) == _SUCCESS) { + ret = rtw_ack_tx_wait23a(pxmitpriv, timeout_ms); + } + + pxmitpriv->ack_tx = false; + mutex_unlock(&pxmitpriv->ack_tx_mutex); + + return ret; +} + +static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) +{ + u8 *ssid_ie; + int ssid_len_ori; + int len_diff = 0; + u8 *next_ie; + u32 remain_len; + + ssid_ie = rtw_get_ie23a(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); + + /* DBG_8723A("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", + __func__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ + + if (ssid_ie && ssid_len_ori > 0) { + switch (hidden_ssid_mode) + { + case 1: + next_ie = ssid_ie + 2 + ssid_len_ori; + remain_len = 0; + + remain_len = ies_len -(next_ie-ies); + + ssid_ie[1] = 0; + memcpy(ssid_ie+2, next_ie, remain_len); + len_diff -= ssid_len_ori; + + break; + case 2: + memset(&ssid_ie[2], 0, ssid_len_ori); + break; + default: + break; + } + } + + return len_diff; +} + +void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int rate_len; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; +#ifdef CONFIG_8723AU_AP_MODE + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + u8 *wps_ie; + u32 wps_ielen; + u8 sr = 0; + int len_diff; + + /* DBG_8723A("%s\n", __func__); */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) { + DBG_8723A("%s, alloc mgnt frame fail\n", __func__); + return; + } +#ifdef CONFIG_8723AU_AP_MODE + spin_lock_bh(&pmlmepriv->bcn_update_lock); +#endif + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->qsel = 0x10; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, bc_addr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(cur_network)); + + SetSeqNum(pwlanhdr, 0 /*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + SetFrameSubType(pframe, WIFI_BEACON); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { + /* DBG_8723A("ie len =%d\n", cur_network->IELength); */ +#ifdef CONFIG_8723AU_P2P + /* for P2P : Primary Device Type & Device Name */ + u32 insert_len = 0; + wps_ie = rtw_get_wps_ie23a(cur_network->IEs + _FIXED_IE_LENGTH_, + cur_network->IELength - + _FIXED_IE_LENGTH_, NULL, &wps_ielen); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wps_ie && + wps_ielen > 0) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie, *pframe_wscie; + + wps_offset = (uint)(wps_ie - cur_network->IEs); + + premainder_ie = wps_ie + wps_ielen; + + remainder_ielen = cur_network->IELength - wps_offset - + wps_ielen; + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + if (pmlmepriv->wps_beacon_ie && + pmlmepriv->wps_beacon_ie_len>0) { + memcpy(pframe, cur_network->IEs, + wps_offset); + pframe += wps_offset; + pattrib->pktlen += wps_offset; + + memcpy(pframe, pmlmepriv->wps_beacon_ie, + pmlmepriv->wps_beacon_ie_len); + pframe += pmlmepriv->wps_beacon_ie_len; + pattrib->pktlen += + pmlmepriv->wps_beacon_ie_len; + + /* copy remainder_ie to pframe */ + memcpy(pframe, premainder_ie, + remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } else { + memcpy(pframe, cur_network->IEs, + cur_network->IELength); + pframe += cur_network->IELength; + pattrib->pktlen += + cur_network->IELength; + } + } else { + pframe_wscie = pframe + wps_offset; + memcpy(pframe, cur_network->IEs, + wps_offset + wps_ielen); + pframe += (wps_offset + wps_ielen); + pattrib->pktlen += (wps_offset + wps_ielen); + + /* now pframe is end of wsc ie, insert Primary + Device Type & Device Name */ + /* Primary Device Type */ + /* Type: */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + insert_len += 2; + + /* Length: */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(0x0008); + insert_len += 2; + + /* Value: */ + /* Category ID */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + insert_len += 2; + + /* OUI */ + *(u32*) (pframe + insert_len) = + cpu_to_be32(WPSOUI); + insert_len += 4; + + /* Sub Category ID */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + insert_len += 2; + + /* Device Name */ + /* Type: */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(WPS_ATTR_DEVICE_NAME); + insert_len += 2; + + /* Length: */ + *(u16*) (pframe + insert_len) = + cpu_to_be16(pwdinfo->device_name_len); + insert_len += 2; + + /* Value: */ + memcpy(pframe + insert_len, + pwdinfo->device_name, + pwdinfo->device_name_len); + insert_len += pwdinfo->device_name_len; + + /* update wsc ie length */ + *(pframe_wscie+1) = (wps_ielen -2) + insert_len; + + /* pframe move to end */ + pframe+= insert_len; + pattrib->pktlen += insert_len; + + /* copy remainder_ie to pframe */ + memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } + } else +#endif /* CONFIG_8723AU_P2P */ + memcpy(pframe, cur_network->IEs, cur_network->IELength); + len_diff = update_hidden_ssid(pframe + _BEACON_IE_OFFSET_, + cur_network->IELength - + _BEACON_IE_OFFSET_, + pmlmeinfo->hidden_ssid_mode); + pframe += (cur_network->IELength+len_diff); + pattrib->pktlen += (cur_network->IELength+len_diff); + + wps_ie = rtw_get_wps_ie23a(pmgntframe->buf_addr + TXDESC_OFFSET+ + sizeof (struct ieee80211_hdr_3addr) + + _BEACON_IE_OFFSET_, pattrib->pktlen - + sizeof (struct ieee80211_hdr_3addr) - + _BEACON_IE_OFFSET_, NULL, + &wps_ielen); + if (wps_ie && wps_ielen > 0) { + rtw_get_wps_attr_content23a(wps_ie, wps_ielen, + WPS_ATTR_SELECTED_REGISTRAR, + (u8*)&sr, NULL); + } + if (sr != 0) + set_fwstate(pmlmepriv, WIFI_UNDER_WPS); + else + _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); + +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + u32 len; + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + len = pmlmepriv->p2p_beacon_ie_len; + if (pmlmepriv->p2p_beacon_ie && len > 0) + memcpy(pframe, + pmlmepriv->p2p_beacon_ie, len); + } else + len = build_beacon_p2p_ie23a(pwdinfo, pframe); + + pframe += len; + pattrib->pktlen += len; + + if (true == pwdinfo->wfd_info->wfd_enable) { + len = build_beacon_wfd_ie(pwdinfo, pframe); + } else { + len = 0; + if (pmlmepriv->wfd_beacon_ie && + pmlmepriv->wfd_beacon_ie_len>0) { + len = pmlmepriv->wfd_beacon_ie_len; + memcpy(pframe, + pmlmepriv->wfd_beacon_ie, len); + } + } + pframe += len; + pattrib->pktlen += len; + } +#endif /* CONFIG_8723AU_P2P */ + + goto _issue_bcn; + } + + /* below for ad-hoc mode */ + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + + memcpy(pframe, (unsigned char *) + rtw_get_beacon_interval23a_from_ie(cur_network->IEs), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + + memcpy(pframe, (unsigned char *) + rtw_get_capability23a_from_ie(cur_network->IEs), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* SSID */ + pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len, + cur_network->Ssid.ssid, &pattrib->pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + ((rate_len > 8)? 8: rate_len), + cur_network->SupportedRates, &pattrib->pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + &cur_network->Configuration.DSConfig, + &pattrib->pktlen); + + /* if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ + { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, + (unsigned char *)&ATIMWindow, + &pattrib->pktlen); + + /* ERP IE */ + pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1, + &erpinfo, &pattrib->pktlen); + } + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + rate_len - 8, + cur_network->SupportedRates + 8, + &pattrib->pktlen); + + /* todo:HT for adhoc */ + +_issue_bcn: + +#ifdef CONFIG_8723AU_AP_MODE + pmlmepriv->update_bcn = false; + + spin_unlock_bh(&pmlmepriv->bcn_update_lock); +#endif + + if ((pattrib->pktlen + TXDESC_SIZE) > 512) { + DBG_8723A("beacon frame too large\n"); + return; + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + /* DBG_8723A("issue bcn_sz =%d\n", pattrib->last_txcmdsz); */ + if (timeout_ms > 0) + dump_mgntframe23a_and_wait(padapter, pmgntframe, timeout_ms); + else + dump_mgntframe23a(padapter, pmgntframe); +} + +void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, + u8 is_valid_p2p_probereq) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac, *bssid; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; +#ifdef CONFIG_8723AU_AP_MODE + u8 *pwps_ie; + uint wps_ielen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + unsigned int rate_len; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + u8 *ssid_ie; + int ssid_ielen; + int ssid_ielen_diff; + u8 buf[MAX_IE_SZ]; + u8 *ies; + + /* DBG_8723A("%s\n", __func__); */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + DBG_8723A("%s, alloc mgnt frame fail\n", __func__); + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + mac = myid(&padapter->eeprompriv); + bssid = cur_network->MacAddress; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr2, mac); + ether_addr_copy(pwlanhdr->addr3, bssid); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(fctrl, WIFI_PROBERSP); + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = pattrib->hdrlen; + pframe += pattrib->hdrlen; + + if (cur_network->IELength > MAX_IE_SZ) + return; + +#ifdef CONFIG_8723AU_AP_MODE + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + pwps_ie = rtw_get_wps_ie23a(cur_network->IEs + + _FIXED_IE_LENGTH_, + cur_network->IELength - + _FIXED_IE_LENGTH_, NULL, + &wps_ielen); + + /* inerset & update wps_probe_resp_ie */ + if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && + (wps_ielen > 0)) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie; + + wps_offset = (uint)(pwps_ie - cur_network->IEs); + + premainder_ie = pwps_ie + wps_ielen; + + remainder_ielen = cur_network->IELength - wps_offset - + wps_ielen; + + memcpy(pframe, cur_network->IEs, wps_offset); + pframe += wps_offset; + pattrib->pktlen += wps_offset; + + /* to get ie data len */ + wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1]; + if ((wps_offset+wps_ielen+2)<= MAX_IE_SZ) { + memcpy(pframe, pmlmepriv->wps_probe_resp_ie, + wps_ielen+2); + pframe += wps_ielen+2; + pattrib->pktlen += wps_ielen+2; + } + + if ((wps_offset+wps_ielen+2+remainder_ielen) <= + MAX_IE_SZ) { + memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } + } else { + memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pattrib->pktlen += cur_network->IELength; + } + + /* retrieve SSID IE from cur_network->Ssid */ + ies = pmgntframe->buf_addr + TXDESC_OFFSET + + sizeof(struct ieee80211_hdr_3addr); + + ssid_ie = rtw_get_ie23a(ies+_FIXED_IE_LENGTH_, _SSID_IE_, + &ssid_ielen, + (pframe-ies)-_FIXED_IE_LENGTH_); + + ssid_ielen_diff = cur_network->Ssid.ssid_len - ssid_ielen; + + if (ssid_ie && cur_network->Ssid.ssid_len) { + uint remainder_ielen; + u8 *remainder_ie; + remainder_ie = ssid_ie + 2; + remainder_ielen = (pframe-remainder_ie); + + DBG_8723A_LEVEL(_drv_warning_, FUNC_ADPT_FMT + " remainder_ielen > MAX_IE_SZ\n", + FUNC_ADPT_ARG(padapter)); + if (remainder_ielen > MAX_IE_SZ) { + remainder_ielen = MAX_IE_SZ; + } + + memcpy(buf, remainder_ie, remainder_ielen); + memcpy(remainder_ie+ssid_ielen_diff, buf, + remainder_ielen); + *(ssid_ie+1) = cur_network->Ssid.ssid_len; + memcpy(ssid_ie+2, cur_network->Ssid.ssid, + cur_network->Ssid.ssid_len); + + pframe += ssid_ielen_diff; + pattrib->pktlen += ssid_ielen_diff; + } + } else +#endif + { + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + + memcpy(pframe, (unsigned char *) + rtw_get_beacon_interval23a_from_ie(cur_network->IEs), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + + memcpy(pframe, (unsigned char *) + rtw_get_capability23a_from_ie(cur_network->IEs), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* below for ad-hoc mode */ + + /* SSID */ + pframe = rtw_set_ie23a(pframe, _SSID_IE_, + cur_network->Ssid.ssid_len, + cur_network->Ssid.ssid, &pattrib->pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + ((rate_len > 8)? 8: rate_len), + cur_network->SupportedRates, + &pattrib->pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *) + &cur_network->Configuration.DSConfig, + &pattrib->pktlen); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, + (unsigned char *)&ATIMWindow, + &pattrib->pktlen); + + /* ERP IE */ + pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1, + &erpinfo, &pattrib->pktlen); + } + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + rate_len - 8, + cur_network->SupportedRates + 8, + &pattrib->pktlen); + + /* todo:HT for adhoc */ + } + +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) { + u32 len; + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + /* if pwdinfo->role == P2P_ROLE_DEVICE will call + issue_probersp23a_p2p23a() */ + len = pmlmepriv->p2p_go_probe_resp_ie_len; + if (pmlmepriv->p2p_go_probe_resp_ie && len>0) + memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie, + len); + } else + len = build_probe_resp_p2p_ie23a(pwdinfo, pframe); + + pframe += len; + pattrib->pktlen += len; + + if (true == pwdinfo->wfd_info->wfd_enable) { + len = build_probe_resp_wfd_ie(pwdinfo, pframe, 0); + } else { + len = 0; + if (pmlmepriv->wfd_probe_resp_ie && + pmlmepriv->wfd_probe_resp_ie_len > 0) { + len = pmlmepriv->wfd_probe_resp_ie_len; + memcpy(pframe, pmlmepriv->wfd_probe_resp_ie, + len); + } + } + pframe += len; + pattrib->pktlen += len; + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static int _issue_probereq23a(struct rtw_adapter *padapter, + struct cfg80211_ssid *pssid, u8 *da, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + int bssrate_len = 0; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("+issue_probereq23a\n")); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + mac = myid(&padapter->eeprompriv); + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + if (da) { + /* unicast probe request frame */ + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr3, da); + } else { + /* broadcast probe request frame */ + ether_addr_copy(pwlanhdr->addr1, bc_addr); + ether_addr_copy(pwlanhdr->addr3, bc_addr); + } + + ether_addr_copy(pwlanhdr->addr2, mac); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_PROBEREQ); + + pframe += sizeof (struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr); + + if (pssid) + pframe = rtw_set_ie23a(pframe, _SSID_IE_, pssid->ssid_len, + pssid->ssid, &pattrib->pktlen); + else + pframe = rtw_set_ie23a(pframe, _SSID_IE_, 0, NULL, + &pattrib->pktlen); + + get_rate_set23a(padapter, bssrate, &bssrate_len); + + if (bssrate_len > 8) { + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + bssrate, &pattrib->pktlen); + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + (bssrate_len - 8), (bssrate + 8), + &pattrib->pktlen); + } else { + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + bssrate_len, bssrate, &pattrib->pktlen); + } + + /* add wps_ie for wps2.0 */ + if (pmlmepriv->wps_probe_req_ie_len>0 && pmlmepriv->wps_probe_req_ie) { + memcpy(pframe, pmlmepriv->wps_probe_req_ie, + pmlmepriv->wps_probe_req_ie_len); + pframe += pmlmepriv->wps_probe_req_ie_len; + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz)); + + if (wait_ack) { + ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); + } else { + dump_mgntframe23a(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +inline void issue_probereq23a(struct rtw_adapter *padapter, + struct cfg80211_ssid *pssid, u8 *da) +{ + _issue_probereq23a(padapter, pssid, da, false); +} + +int issue_probereq23a_ex23a(struct rtw_adapter *padapter, + struct cfg80211_ssid *pssid, u8 *da, + int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + unsigned long start = jiffies; + + do { + ret = _issue_probereq23a(padapter, pssid, da, + wait_ms > 0 ? true : false); + + i++; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + + } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } + + if (try_cnt && wait_ms) { + if (da) + DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " + "in %u ms\n", FUNC_ADPT_ARG(padapter), + MAC_ARG(da), rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + else + DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), + rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + } +exit: + return ret; +} + +/* if psta == NULL, indiate we are station(client) now... */ +void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta, + unsigned short status) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int val32; + unsigned short val16; + int use_shared_key = 0; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_AUTH); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + if (psta) { /* for AP mode */ +#ifdef CONFIG_8723AU_AP_MODE + + ether_addr_copy(pwlanhdr->addr1, psta->hwaddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv)); + + /* setting auth algo number */ + val16 = (u16)psta->authalg; + + if (status != WLAN_STATUS_SUCCESS) + val16 = 0; + + if (val16) { + val16 = cpu_to_le16(val16); + use_shared_key = 1; + } + + pframe = rtw_set_fixed_ie23a(pframe, _AUTH_ALGM_NUM_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* setting auth seq number */ + val16 = (u16)psta->auth_seq; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie23a(pframe, _AUTH_SEQ_NUM_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* setting status code... */ + val16 = status; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* added challenging text... */ + if ((psta->auth_seq == 2) && + (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) + pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128, + psta->chg_txt, &pattrib->pktlen); +#endif + } else { + ether_addr_copy(pwlanhdr->addr1, + get_my_bssid23a(&pmlmeinfo->network)); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, + get_my_bssid23a(&pmlmeinfo->network)); + + /* setting auth algo number */ + /* 0:OPEN System, 1:Shared key */ + val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)? 1: 0; + if (val16) { + val16 = cpu_to_le16(val16); + use_shared_key = 1; + } + /* DBG_8723A("%s auth_algo = %s auth_seq =%d\n", __func__, + (pmlmeinfo->auth_algo == 0)?"OPEN":"SHARED", + pmlmeinfo->auth_seq); */ + + /* setting IV for auth seq #3 */ + if ((pmlmeinfo->auth_seq == 3) && + (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && + (use_shared_key == 1)) { + /* DBG_8723A("==> iv(%d), key_index(%d)\n", + pmlmeinfo->iv, pmlmeinfo->key_index); */ + val32 = ((pmlmeinfo->iv++) | + (pmlmeinfo->key_index << 30)); + val32 = cpu_to_le32(val32); + pframe = rtw_set_fixed_ie23a(pframe, 4, + (unsigned char *)&val32, + &pattrib->pktlen); + + pattrib->iv_len = 4; + } + + pframe = rtw_set_fixed_ie23a(pframe, _AUTH_ALGM_NUM_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* setting auth seq number */ + val16 = pmlmeinfo->auth_seq; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie23a(pframe, _AUTH_SEQ_NUM_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* setting status code... */ + val16 = status; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_, + (unsigned char *)&val16, + &pattrib->pktlen); + + /* then checking to see if sending challenging text... */ + if ((pmlmeinfo->auth_seq == 3) && + (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && + (use_shared_key == 1)) { + pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128, + pmlmeinfo->chg_txt, + &pattrib->pktlen); + + SetPrivacy(fctrl); + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + + pattrib->encrypt = _WEP40_; + + pattrib->icv_len = 4; + + pattrib->pktlen += pattrib->icv_len; + } + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + rtw_wep_encrypt23a(padapter, pmgntframe); + DBG_8723A("%s\n", __func__); + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status, + struct sta_info *pstat, int pkt_type) +{ +#ifdef CONFIG_8723AU_AP_MODE + struct xmit_frame *pmgntframe; + struct ieee80211_hdr *pwlanhdr; + struct pkt_attrib *pattrib; + unsigned char *pbuf, *pframe; + unsigned short val; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + u8 *ie = pnetwork->IEs; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + DBG_8723A("%s\n", __func__); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + pwlanhdr->frame_control = 0; + + ether_addr_copy(pwlanhdr->addr1, pstat->hwaddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) + SetFrameSubType(pwlanhdr, pkt_type); + else + return; + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen += pattrib->hdrlen; + pframe += pattrib->hdrlen; + + /* capability */ + val = *(unsigned short *)rtw_get_capability23a_from_ie(ie); + + pframe = rtw_set_fixed_ie23a(pframe, _CAPABILITY_, + (unsigned char *)&val, &pattrib->pktlen); + + status = cpu_to_le16(status); + pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_, + (unsigned char *)&status, + &pattrib->pktlen); + + val = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); + pframe = rtw_set_fixed_ie23a(pframe, _ASOC_ID_, (unsigned char *)&val, + &pattrib->pktlen); + + if (pstat->bssratelen <= 8) { + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + pstat->bssratelen, pstat->bssrateset, + &pattrib->pktlen); + } else { + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + pstat->bssrateset, &pattrib->pktlen); + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + pstat->bssratelen - 8, + pstat->bssrateset + 8, &pattrib->pktlen); + } + + if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { + uint ie_len = 0; + + /* FILL HT CAP INFO IE */ + /* p = hostapd_eid_ht_capabilities_info(hapd, p); */ + pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, + _HT_CAPABILITY_IE_, &ie_len, + pnetwork->IELength - _BEACON_IE_OFFSET_); + if (pbuf && ie_len>0) { + memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + + /* FILL HT ADD INFO IE */ + /* p = hostapd_eid_ht_operation(hapd, p); */ + pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, + &ie_len, + pnetwork->IELength - _BEACON_IE_OFFSET_); + if (pbuf && ie_len > 0) { + memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + } + + /* FILL WMM IE */ + if ((pstat->flags & WLAN_STA_WME) && pmlmepriv->qospriv.qos_option) { + uint ie_len = 0; + unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, + 0x01, 0x01}; + + for (pbuf = ie + _BEACON_IE_OFFSET_; ; pbuf += (ie_len + 2)) { + pbuf = rtw_get_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, + &ie_len, (pnetwork->IELength - + _BEACON_IE_OFFSET_ - + (ie_len + 2))); + if (pbuf && !memcmp(pbuf + 2, WMM_PARA_IE, 6)) { + memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + + break; + } + + if ((!pbuf) || (ie_len == 0)) + break; + } + } + + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) { + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6, + REALTEK_96B_IE23A, &pattrib->pktlen); + } + + /* add WPS IE ie for wps 2.0 */ + if (pmlmepriv->wps_assoc_resp_ie && + pmlmepriv->wps_assoc_resp_ie_len > 0) { + memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, + pmlmepriv->wps_assoc_resp_ie_len); + + pframe += pmlmepriv->wps_assoc_resp_ie_len; + pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; + } + +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && + pwdinfo->wfd_info->wfd_enable) { + wfdielen = build_assoc_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +#endif +} + +void issue_assocreq23a(struct rtw_adapter *padapter) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe, *p; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned short val16; + unsigned int i, j, ie_len, index = 0; + unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; + struct ndis_802_11_var_ies *pIE; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + int bssrate_len = 0, sta_bssrate_len = 0; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 p2pie[255] = { 0x00 }; + u16 p2pielen = 0; + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + ether_addr_copy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network)); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ASSOCREQ); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + /* caps */ + memcpy(pframe, rtw_get_capability23a_from_ie(pmlmeinfo->network.IEs), + 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* listen interval */ + /* todo: listen interval for power saving */ + val16 = cpu_to_le16(3); + memcpy(pframe, (unsigned char *)&val16, 2); + pframe += 2; + pattrib->pktlen += 2; + + /* SSID */ + pframe = rtw_set_ie23a(pframe, _SSID_IE_, + pmlmeinfo->network.Ssid.ssid_len, + pmlmeinfo->network.Ssid.ssid, &pattrib->pktlen); + + /* supported rate & extended supported rate */ + + get_rate_set23a(padapter, sta_bssrate, &sta_bssrate_len); + /* DBG_8723A("sta_bssrate_len =%d\n", sta_bssrate_len); */ + + /* for JAPAN, channel 14 can only uses B Mode(CCK) */ + if (pmlmeext->cur_channel == 14) + sta_bssrate_len = 4; + + /* for (i = 0; i < sta_bssrate_len; i++) { */ + /* DBG_8723A("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */ + /* */ + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + DBG_8723A("network.SupportedRates[%d]=%02X\n", i, + pmlmeinfo->network.SupportedRates[i]); + } + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + + /* Check if the AP's supported rates are also + supported by STA. */ + for (j = 0; j < sta_bssrate_len; j++) { + /* Avoid the proprietary data rate (22Mbps) of + Handlink WSG-4000 AP */ + if ((pmlmeinfo->network.SupportedRates[i] | + IEEE80211_BASIC_RATE_MASK) == + (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) { + /* DBG_8723A("match i = %d, j =%d\n", i, j); */ + break; + } + } + + if (j == sta_bssrate_len) { + /* the rate is not supported by STA */ + DBG_8723A("%s(): the rate[%d]=%02X is not supported by " + "STA!\n", __func__, i, + pmlmeinfo->network.SupportedRates[i]); + } else { + /* the rate is supported by STA */ + bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; + } + } + + bssrate_len = index; + DBG_8723A("bssrate_len = %d\n", bssrate_len); + + if (bssrate_len == 0) { + rtw_free_xmitbuf23a(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe23a(pxmitpriv, pmgntframe); + goto exit; /* don't connect to AP if no joint supported rate */ + } + + if (bssrate_len > 8) { + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8, + bssrate, &pattrib->pktlen); + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, + (bssrate_len - 8), (bssrate + 8), + &pattrib->pktlen); + } else + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, + bssrate_len, bssrate, &pattrib->pktlen); + + /* RSN */ + p = rtw_get_ie23a((pmlmeinfo->network.IEs + + sizeof(struct ndis_802_11_fixed_ies)), _RSN_IE_2_, + &ie_len, (pmlmeinfo->network.IELength - + sizeof(struct ndis_802_11_fixed_ies))); + if (p) + pframe = rtw_set_ie23a(pframe, _RSN_IE_2_, ie_len, (p + 2), + &pattrib->pktlen); + + /* HT caps */ + if (padapter->mlmepriv.htpriv.ht_option == true) { + p = rtw_get_ie23a((pmlmeinfo->network.IEs + + sizeof(struct ndis_802_11_fixed_ies)), + _HT_CAPABILITY_IE_, &ie_len, + (pmlmeinfo->network.IELength - + sizeof(struct ndis_802_11_fixed_ies))); + if ((p != NULL) && (!(is_ap_in_tkip23a(padapter)))) { + memcpy(&pmlmeinfo->HT_caps, (p + 2), + sizeof(struct HT_caps_element)); + + /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ + if (pregpriv->cbw40_enable == 0) { + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= (~(BIT(6) | BIT(1))); + } else { + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= BIT(1); + } + + /* todo: disable SM power save mode */ + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= + 0x000c; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, + (u8 *)(&rf_type)); + /* switch (pregpriv->rf_config) */ + switch (rf_type) + { + case RF_1T1R: + + if (pregpriv->rx_stbc) + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ + + memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R23A, 16); + break; + + case RF_2T2R: + case RF_1T2R: + default: + + /* enable for 2.4/5 GHz */ + if ((pregpriv->rx_stbc == 0x3) || + ((pmlmeext->cur_wireless_mode & + WIRELESS_11_24N) && + /* enable for 2.4GHz */ + (pregpriv->rx_stbc == 0x1)) || + ((pmlmeext->cur_wireless_mode & + WIRELESS_11_5N) && + (pregpriv->rx_stbc == 0x2)) || + /* enable for 5GHz */ + (pregpriv->wifi_spec == 1)) { + DBG_8723A("declare supporting RX " + "STBC\n"); + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ + } + memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R23A, 16); + break; + } + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = + cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); + +#ifdef CONFIG_8723AU_BT_COEXIST + if (BT_1Ant(padapter) == true) { + /* set to 8K */ + pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para &= (u8)~IEEE80211_HT_AMPDU_PARM_FACTOR; +/* pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para |= MAX_AMPDU_FACTOR_8K */ + } +#endif + + pframe = rtw_set_ie23a(pframe, _HT_CAPABILITY_IE_, + ie_len, + (u8 *)&pmlmeinfo->HT_caps, + &pattrib->pktlen); + } + } + + /* vendor specific IE, such as WPA, WMM, WPS */ + for (i = sizeof(struct ndis_802_11_fixed_ies); + i < pmlmeinfo->network.IELength;) { + pIE = (struct ndis_802_11_var_ies *) + (pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) + { + case _VENDOR_SPECIFIC_IE_: + if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) || + !memcmp(pIE->data, WMM_OUI23A, 4) || + !memcmp(pIE->data, WPS_OUI23A, 4)) { + if (!padapter->registrypriv.wifi_spec) { + /* Commented by Kurt 20110629 */ + /* In some older APs, WPS handshake */ + /* would be fail if we append vender + extensions informations to AP */ + if (!memcmp(pIE->data, WPS_OUI23A, 4)) + pIE->Length = 14; + } + pframe = rtw_set_ie23a(pframe, + _VENDOR_SPECIFIC_IE_, + pIE->Length, pIE->data, + &pattrib->pktlen); + } + break; + + default: + break; + } + + i += (pIE->Length + 2); + } + + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6, + REALTEK_96B_IE23A, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) { + if (pmlmepriv->p2p_assoc_req_ie && + pmlmepriv->p2p_assoc_req_ie_len>0) { + memcpy(pframe, pmlmepriv->p2p_assoc_req_ie, + pmlmepriv->p2p_assoc_req_ie_len); + pframe += pmlmepriv->p2p_assoc_req_ie_len; + pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len; + } + } else { + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { + /* Should add the P2P IE in the association + request frame. */ + /* P2P OUI */ + + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101109 */ + /* According to the P2P Specification, the + association request frame should contain + 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Extended Listen Timing */ + /* 3. Device Info */ + /* Commented by Albert 20110516 */ + /* 4. P2P Interface */ + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = + P2P_GRPCAP_PERSISTENT_GROUP | + DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + + /* Extended Listen Timing */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config + Methods (2bytes) + Primary Device + Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device + Name ID field (2bytes) + WPS Device Name + Len field (2bytes) */ + *(u16*) (p2pie + p2pielen) = + cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, + myid(&padapter->eeprompriv), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. + Noted by P2P specification. */ + if ((pwdinfo->ui_got_wps_info == + P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) || + (pwdinfo->ui_got_wps_info == + P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)) + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); + else + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(WPS_CONFIG_METHOD_PBC); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + /* No Secondary Device Type List */ + p2pie[p2pielen++] = 0x00; + + /* Device Name */ + /* Type: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = + cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, + pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + /* P2P Interface */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTERFACE; + + /* Length: */ + *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x000D); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_addr, + ETH_ALEN); /* P2P Device Address */ + p2pielen += ETH_ALEN; + + /* P2P Interface Address Count */ + p2pie[p2pielen++] = 1; + + memcpy(p2pie + p2pielen, pwdinfo->device_addr, + ETH_ALEN); /* P2P Interface Address List */ + p2pielen += ETH_ALEN; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, + p2pielen, (unsigned char *)p2pie, + &pattrib->pktlen); + + /* wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe);*/ + /* pframe += wfdielen; */ + /* pattrib->pktlen += wfdielen; */ + } + } + + if (true == pwdinfo->wfd_info->wfd_enable) { + wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } else if (pmlmepriv->wfd_assoc_req_ie != NULL && + pmlmepriv->wfd_assoc_req_ie_len > 0) { + /* WFD IE */ + memcpy(pframe, pmlmepriv->wfd_assoc_req_ie, + pmlmepriv->wfd_assoc_req_ie_len); + pattrib->pktlen += pmlmepriv->wfd_assoc_req_ie_len; + pframe += pmlmepriv->wfd_assoc_req_ie_len; + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + dump_mgntframe23a(padapter, pmgntframe); + + ret = _SUCCESS; + +exit: + pmlmepriv->assoc_req_len = 0; + if (ret == _SUCCESS) { + kfree(pmlmepriv->assoc_req); + pmlmepriv->assoc_req = kmalloc(pattrib->pktlen, GFP_ATOMIC); + if (pmlmepriv->assoc_req) { + memcpy(pmlmepriv->assoc_req, pwlanhdr, + pattrib->pktlen); + pmlmepriv->assoc_req_len = pattrib->pktlen; + } + } else + kfree(pmlmepriv->assoc_req); + + return; +} + +/* when wait_ack is ture, this function shoule be called at process context */ +static int _issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da, + unsigned int power_mode, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + + /* DBG_8723A("%s:%d\n", __func__, power_mode); */ + + if (!padapter) + goto exit; + + pxmitpriv = &padapter->xmitpriv; + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->retry_ctrl = false; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); + + if (power_mode) + SetPwrMgt(fctrl); + + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_DATA_NULL); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); + else { + dump_mgntframe23a(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +/* when wait_ms >0 , this function shoule be called at process context */ +/* da == NULL for station mode */ +int issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da, + unsigned int power_mode, int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + unsigned long start = jiffies; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* da == NULL, assum it's null data for sta to ap*/ + if (da == NULL) + da = get_my_bssid23a(&pmlmeinfo->network); + + do { + ret = _issue_nulldata23a(padapter, da, power_mode, + wait_ms > 0 ? true : false); + + i++; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + + } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } + + if (try_cnt && wait_ms) { + if (da) + DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " + "in %u ms\n", FUNC_ADPT_ARG(padapter), + MAC_ARG(da), rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + else + DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), + rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + } +exit: + return ret; +} + +/* when wait_ack is ture, this function shoule be called at process context */ +static int _issue_qos_nulldata23a(struct rtw_adapter *padapter, + unsigned char *da, u16 tid, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl, *qc; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + DBG_8723A("%s\n", __func__); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + pattrib->hdrlen += 2; + pattrib->qos_en = true; + pattrib->eosp = 1; + pattrib->ack_policy = 0; + pattrib->mdata = 0; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); + + if (pattrib->mdata) + SetMData(fctrl); + + qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); + + SetPriority(qc, tid); + + SetEOSP(qc, pattrib->eosp); + + SetAckpolicy(qc, pattrib->ack_policy); + + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); + + pframe += sizeof(struct ieee80211_qos_hdr); + pattrib->pktlen = sizeof(struct ieee80211_qos_hdr); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); + else { + dump_mgntframe23a(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +/* when wait_ms >0 , this function shoule be called at process context */ +/* da == NULL for station mode */ +int issue_qos_nulldata23a(struct rtw_adapter *padapter, unsigned char *da, + u16 tid, int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + unsigned long start = jiffies; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* da == NULL, assum it's null data for sta to ap*/ + if (da == NULL) + da = get_my_bssid23a(&pmlmeinfo->network); + + do { + ret = _issue_qos_nulldata23a(padapter, da, tid, + wait_ms > 0 ? true : false); + + i++; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } + + if (try_cnt && wait_ms) { + if (da) + DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " + "in %u ms\n", FUNC_ADPT_ARG(padapter), + MAC_ARG(da), rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + else + DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), + rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + } +exit: + return ret; +} + +static int _issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da, + unsigned short reason, u8 wait_ack) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + int ret = _FAIL; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + /* DBG_8723A("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */ + +#ifdef CONFIG_8723AU_P2P + if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && + (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { + mod_timer(&pwdinfo->reset_ch_sitesurvey, + jiffies + msecs_to_jiffies(10)); + } +#endif /* CONFIG_8723AU_P2P */ + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->retry_ctrl = false; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, da); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_DEAUTH); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + reason = cpu_to_le16(reason); + pframe = rtw_set_fixed_ie23a(pframe, WLAN_REASON_PREV_AUTH_NOT_VALID, + (unsigned char *)&reason, + &pattrib->pktlen); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe); + else { + dump_mgntframe23a(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +int issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da, + unsigned short reason) +{ + DBG_8723A("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); + return _issue_deauth23a(padapter, da, reason, false); +} + +int issue_deauth23a_ex23a(struct rtw_adapter *padapter, u8 *da, + unsigned short reason, int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + unsigned long start = jiffies; + + do { + ret = _issue_deauth23a(padapter, da, reason, + wait_ms >0 ? true : false); + + i++; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + msleep(wait_ms); + + } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; + goto exit; + } + + if (try_cnt && wait_ms) { + if (da) + DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d " + "in %u ms\n", FUNC_ADPT_ARG(padapter), + MAC_ARG(da), rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + else + DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), + rtw_get_oper_ch23a(padapter), + ret == _SUCCESS?", acked":"", i, try_cnt, + jiffies_to_msecs(jiffies - start)); + } +exit: + return ret; +} + +void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter, + u8 *ra, u8 new_ch, u8 ch_offset) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u8 category, action; + + DBG_8723A(FUNC_NDEV_FMT" ra ="MAC_FMT", ch:%u, offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra), + new_ch, ch_offset); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, ra); /* RA */ + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); /* TA */ + ether_addr_copy(pwlanhdr->addr3, ra); /* DA = RA */ + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + /* category, action */ + category = WLAN_CATEGORY_SPECTRUM_MGMT; + action = WLAN_ACTION_SPCT_CHL_SWITCH; + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + + pframe = rtw_set_ie23a_ch_switch (pframe, &pattrib->pktlen, 0, + new_ch, 0); + pframe = rtw_set_ie23a_secondary_ch_offset(pframe, &pattrib->pktlen, + hal_ch_offset_to_secondary_ch_offset23a(ch_offset)); + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr, + unsigned char action, unsigned short status) +{ + u8 category = WLAN_CATEGORY_BACK; + u16 start_seq; + u16 BA_para_set; + u16 reason_code; + u16 BA_timeout_value; + u16 BA_starting_seqctrl; + int max_rx_ampdu_factor; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + u8 *pframe; + struct ieee80211_hdr *pwlanhdr; + u16 *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct registry_priv *pregpriv = &padapter->registrypriv; +#ifdef CONFIG_8723AU_BT_COEXIST + u8 tendaAPMac[] = {0xC8, 0x3A, 0x35}; +#endif + + DBG_8723A("%s, category =%d, action =%d, status =%d\n", + __func__, category, action, status); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + /* memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); */ + ether_addr_copy(pwlanhdr->addr1, raddr); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + + status = cpu_to_le16(status); + + if (category != 3) + goto out; + + switch (action) + { + case 0: /* ADDBA req */ + do { + pmlmeinfo->dialogToken++; + } while (pmlmeinfo->dialogToken == 0); + pframe = rtw_set_fixed_ie23a(pframe, 1, &pmlmeinfo->dialogToken, + &pattrib->pktlen); + +#ifdef CONFIG_8723AU_BT_COEXIST + if ((BT_1Ant(padapter) == true) && + ((pmlmeinfo->assoc_AP_vendor != broadcomAP) || + memcmp(raddr, tendaAPMac, 3))) { + /* A-MSDU NOT Supported */ + BA_para_set = 0; + /* immediate Block Ack */ + BA_para_set |= (1 << 1) & + IEEE80211_ADDBA_PARAM_POLICY_MASK; + /* TID */ + BA_para_set |= (status << 2) & + IEEE80211_ADDBA_PARAM_TID_MASK; + /* max buffer size is 8 MSDU */ + BA_para_set |= (8 << 6) & + IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + } else +#endif + { + /* immediate ack & 64 buffer size */ + BA_para_set = (0x1002 | ((status & 0xf) << 2)); + } + BA_para_set = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie23a(pframe, 2, + (unsigned char *)&BA_para_set, + &pattrib->pktlen); + + BA_timeout_value = 5000;/* 5ms */ + BA_timeout_value = cpu_to_le16(BA_timeout_value); + pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *) + &BA_timeout_value, + &pattrib->pktlen); + + /* if ((psta = rtw_get_stainfo23a(pstapriv, + pmlmeinfo->network.MacAddress)) != NULL) */ + if ((psta = rtw_get_stainfo23a(pstapriv, raddr))) { + start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; + + DBG_8723A("BA_starting_seqctrl = %d for TID =%d\n", + start_seq, status & 0x07); + + psta->BA_starting_seqctrl[status & 0x07] = start_seq; + + BA_starting_seqctrl = start_seq << 4; + } + + BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl); + pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *)&BA_starting_seqctrl, &pattrib->pktlen); + break; + + case 1: /* ADDBA rsp */ + pframe = rtw_set_fixed_ie23a(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 2, + (unsigned char *)&status, + &pattrib->pktlen); + rtw_hal_get_def_var23a(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, + &max_rx_ampdu_factor); + if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_64K) + BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ + else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_32K) + BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */ + else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_16K) + BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */ + else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_8K) + BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */ + else + BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */ + +#ifdef CONFIG_8723AU_BT_COEXIST + if ((BT_1Ant(padapter) == true) && + ((pmlmeinfo->assoc_AP_vendor != broadcomAP) || + memcmp(raddr, tendaAPMac, 3))) { + /* max buffer size is 8 MSDU */ + BA_para_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + BA_para_set |= (8 << 6) & + IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + } +#endif + + if (pregpriv->ampdu_amsdu == 0)/* disabled */ + BA_para_set = cpu_to_le16(BA_para_set & ~BIT(0)); + else if (pregpriv->ampdu_amsdu == 1)/* enabled */ + BA_para_set = cpu_to_le16(BA_para_set | BIT(0)); + else /* auto */ + BA_para_set = cpu_to_le16(BA_para_set); + + pframe = rtw_set_fixed_ie23a(pframe, 2, + (unsigned char *)&BA_para_set, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); + break; + case 2:/* DELBA */ + BA_para_set = (status & 0x1F) << 3; + BA_para_set = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie23a(pframe, 2, + (unsigned char *)&BA_para_set, + &pattrib->pktlen); + + reason_code = 37;/* Requested from peer STA as it does not + want to use the mechanism */ + reason_code = cpu_to_le16(reason_code); + pframe = rtw_set_fixed_ie23a(pframe, 2, + (unsigned char *)&reason_code, + &pattrib->pktlen); + break; + default: + break; + } + +out: + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter) +{ + struct list_head *plist, *phead, *ptmp; + unsigned char category, action; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct wlan_network *pnetwork = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + u8 InfoContent[16] = {0}; + u8 ICS[8][15]; + + if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) + return; + + if (true == pmlmeinfo->bwmode_updated) + return; + + DBG_8723A("%s\n", __func__); + + category = WLAN_CATEGORY_PUBLIC; + action = ACT_PUBLIC_BSSCOEXIST; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + ether_addr_copy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network)); + ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); + ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network)); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + + /* */ + if (pmlmepriv->num_FortyMHzIntolerant>0) + { + u8 iedata = 0; + + iedata |= BIT(2);/* 20 MHz BSS Width Request */ + + pframe = rtw_set_ie23a(pframe, EID_BSSCoexistence, 1, &iedata, &pattrib->pktlen); + + } + + /* */ + memset(ICS, 0, sizeof(ICS)); + if (pmlmepriv->num_sta_no_ht>0) + { + int i; + + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + + phead = get_list_head(queue); + plist = phead->next; + + list_for_each_safe(plist, ptmp, phead) { + int len; + u8 *p; + struct wlan_bssid_ex *pbss_network; + + pnetwork = container_of(plist, struct wlan_network, + list); + + pbss_network = &pnetwork->network; + + p = rtw_get_ie23a(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); + if ((p == NULL) || (len == 0))/* non-HT */ + { + if ((pbss_network->Configuration.DSConfig<= 0) || (pbss_network->Configuration.DSConfig>14)) + continue; + + ICS[0][pbss_network->Configuration.DSConfig]= 1; + + if (ICS[0][0] == 0) + ICS[0][0] = 1; + } + + } + + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + + for (i = 0;i<8;i++) + { + if (ICS[i][0] == 1) + { + int j, k = 0; + + InfoContent[k] = i; + /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ + k++; + + for (j = 1;j<= 14;j++) + { + if (ICS[i][j]== 1) + { + if (k<16) + { + InfoContent[k] = j; /* channel number */ + /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ + k++; + } + } + } + + pframe = rtw_set_ie23a(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &pattrib->pktlen); + + } + + } + + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +unsigned int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + /* struct recv_reorder_ctrl *preorder_ctrl; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u16 tid; + + if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) + return _SUCCESS; + + psta = rtw_get_stainfo23a(pstapriv, addr); + if (psta == NULL) + return _SUCCESS; + + if (initiator == 0) { /* recipient */ + for (tid = 0; tid < MAXTID; tid++) { + if (psta->recvreorder_ctrl[tid].enable == true) { + DBG_8723A("rx agg disable tid(%d)\n", tid); + issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F)); + psta->recvreorder_ctrl[tid].enable = false; + psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; + } + } + } else if (initiator == 1) { /* originator */ + for (tid = 0; tid < MAXTID; tid++) { + if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { + DBG_8723A("tx agg disable tid(%d)\n", tid); + issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F)); + psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); + + } + } + } + return _SUCCESS; +} + +unsigned int send_beacon23a(struct rtw_adapter *padapter) +{ + u8 bxmitok = false; + int issue = 0; + int poll = 0; + unsigned long start = jiffies; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_VALID, NULL); + do { + issue_beacon23a(padapter, 100); + issue++; + do { + yield(); + rtw23a_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); + poll++; + } while ((poll%10)!= 0 && false == bxmitok && + !padapter->bSurpriseRemoved && + !padapter->bDriverStopped); + + } while (!bxmitok && issue<100 && !padapter->bSurpriseRemoved && + !padapter->bDriverStopped); + + if (padapter->bSurpriseRemoved || padapter->bDriverStopped) + return _FAIL; + + if (!bxmitok) { + DBG_8723A("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms23a(start)); + return _FAIL; + } else { + unsigned int passing_time = jiffies_to_msecs(jiffies - start); + + if (passing_time > 100 || issue > 3) + DBG_8723A("%s success, issue:%d, poll:%d, %u ms\n", + __func__, issue, poll, passing_time); + return _SUCCESS; + } +} + +/**************************************************************************** + +Following are some utitity fuctions for WiFi MLME + +*****************************************************************************/ + +bool IsLegal5GChannel(struct rtw_adapter *Adapter, u8 channel) +{ + + int i = 0; + u8 Channel_5G[45] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, + 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, + 161, 163, 165}; + for (i = 0; i < sizeof(Channel_5G); i++) + if (channel == Channel_5G[i]) + return true; + return false; +} + +void site_survey23a(struct rtw_adapter *padapter) +{ + unsigned char survey_channel = 0, val8; + enum rt_scan_type ScanType = SCAN_PASSIVE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u32 initialgain = 0; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || + (pwdinfo->p2p_info.scan_op_ch_only)) { + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) + survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; + else + survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; + ScanType = SCAN_ACTIVE; + } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) { + /* The driver is in the find phase, it should go through the social channel. */ + int ch_set_idx; + survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx]; + ch_set_idx = rtw_ch_set_search_ch23a(pmlmeext->channel_set, survey_channel); + if (ch_set_idx >= 0) + ScanType = pmlmeext->channel_set[ch_set_idx].ScanType; + else + ScanType = SCAN_ACTIVE; + } else +#endif /* CONFIG_8723AU_P2P */ + { + struct rtw_ieee80211_channel *ch; + if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { + ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; + survey_channel = ch->hw_value; + ScanType = (ch->flags & IEEE80211_CHAN_NO_IR) ? SCAN_PASSIVE : SCAN_ACTIVE; +} + } + + if (survey_channel != 0) { + /* PAUSE 4-AC Queue when site_survey23a */ + /* rtw23a_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + /* val8 |= 0x0f; */ + /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + if (pmlmeext->sitesurvey_res.channel_idx == 0) + set_channel_bwmode23a(padapter, survey_channel, + HAL_PRIME_CHNL_OFFSET_DONT_CARE, + HT_CHANNEL_WIDTH_20); + else + SelectChannel23a(padapter, survey_channel); + + if (ScanType == SCAN_ACTIVE) /* obey the channel plan setting... */ + { +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || + rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) + ) + { + issue23a_probereq_p2p(padapter, NULL); + issue23a_probereq_p2p(padapter, NULL); + issue23a_probereq_p2p(padapter, NULL); + } + else +#endif /* CONFIG_8723AU_P2P */ + { + int i; + for (i = 0;isitesurvey_res.ssid[i].ssid_len) { + /* todo: to issue two probe req??? */ + issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); + } + } + + if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + /* todo: to issue two probe req??? */ + issue_probereq23a(padapter, NULL, NULL); + /* msleep(SURVEY_TO>>1); */ + issue_probereq23a(padapter, NULL, NULL); + } + } + } + + set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); + } else { + + /* channel number is 0 or this channel is not valid. */ + + +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) + { + if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) + { + /* Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */ + /* This will let the following flow to run the scanning end. */ + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); + } + } + + if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) + { + /* Set the P2P State to the listen state of find phase and set the current channel to the listen channel */ + set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + + initialgain = 0xff; /* restore RX GAIN */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); + /* turn on dynamic functions */ + Restore_DM_Func_Flag23a(padapter); + /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */ + + mod_timer(&pwdinfo->find_phase_timer, jiffies + + msecs_to_jiffies(pwdinfo->listen_dwell * 100)); + } else +#endif /* CONFIG_8723AU_P2P */ + { +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); +#endif /* CONFIG_8723AU_P2P */ + + pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; + + /* switch back to the original channel */ + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + /* flush 4-AC Queue after site_survey23a */ + /* val8 = 0; */ + /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ + + /* config MSR */ + Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); + + initialgain = 0xff; /* restore RX GAIN */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); + /* turn on dynamic functions */ + Restore_DM_Func_Flag23a(padapter); + /* Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ + + if (is_client_associated_to_ap23a(padapter) == true) + { + issue_nulldata23a(padapter, NULL, 0, 3, 500); + + } + + val8 = 0; /* survey done */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + report_surveydone_event23a(padapter); + + pmlmeext->chan_scan_time = SURVEY_TO; + pmlmeext->sitesurvey_res.state = SCAN_DISABLE; + + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + + } + } + + return; +} + +/* collect bss info from Beacon and Probe request/response frames. */ +u8 collect_bss_info23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) +{ + int i; + u32 len; + u8 *p; + u16 val16; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + u32 packet_len = skb->len; + u8 ie_offset; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + len = packet_len - sizeof(struct ieee80211_hdr_3addr); + + if (len > MAX_IE_SZ) + { + /* DBG_8723A("IE too long for survey event\n"); */ + return _FAIL; + } + + memset(bssid, 0, sizeof(struct wlan_bssid_ex)); + + if (ieee80211_is_beacon(hdr->frame_control)) { + bssid->reserved = 1; + ie_offset = _BEACON_IE_OFFSET_; + } else { + /* FIXME : more type */ + if (ieee80211_is_probe_req(hdr->frame_control)) { + ie_offset = _PROBEREQ_IE_OFFSET_; + bssid->reserved = 2; + } else if (ieee80211_is_probe_resp(hdr->frame_control)) { + ie_offset = _PROBERSP_IE_OFFSET_; + bssid->reserved = 3; + } else { + bssid->reserved = 0; + ie_offset = _FIXED_IE_LENGTH_; + } + } + + bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; + + /* below is to copy the information element */ + bssid->IELength = len; + memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); + + /* get the signal strength */ + bssid->Rssi = precv_frame->attrib.phy_info.RecvSignalPower; /* in dBM.raw data */ + bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ + bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ + + /* checking SSID */ + if ((p = rtw_get_ie23a(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset)) == NULL) + { + DBG_8723A("marc: cannot find SSID for survey event\n"); + return _FAIL; + } + + if (*(p + 1)) { + if (len > IEEE80211_MAX_SSID_LEN) { + DBG_8723A("%s()-%d: IE too long (%d) for survey " + "event\n", __func__, __LINE__, len); + return _FAIL; + } + memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1)); + bssid->Ssid.ssid_len = *(p + 1); + } else { + bssid->Ssid.ssid_len = 0; + } + + memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + + /* checking rate info... */ + i = 0; + p = rtw_get_ie23a(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) + { + if (len > NDIS_802_11_LENGTH_RATES_EX) + { + DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + return _FAIL; + } + memcpy(bssid->SupportedRates, (p + 2), len); + i = len; + } + + p = rtw_get_ie23a(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) + { + if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) + { + DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); + return _FAIL; + } + memcpy(bssid->SupportedRates + i, (p + 2), len); + } + + /* todo: */ + { + bssid->NetworkTypeInUse = Ndis802_11OFDM24; + } + + if (bssid->IELength < 12) + return _FAIL; + + /* Checking for DSConfig */ + p = rtw_get_ie23a(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); + + bssid->Configuration.DSConfig = 0; + bssid->Configuration.Length = 0; + + if (p) + { + bssid->Configuration.DSConfig = *(p + 2); + } + else + {/* In 5G, some ap do not have DSSET IE */ + /* checking HT info for channel */ + p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); + if (p) + { + struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); + bssid->Configuration.DSConfig = HT_info->primary_channel; + } + else + { /* use current channel */ + bssid->Configuration.DSConfig = rtw_get_oper_ch23a(padapter); + } + } + + if (ieee80211_is_probe_req(hdr->frame_control)) { + /* FIXME */ + bssid->InfrastructureMode = Ndis802_11Infrastructure; + ether_addr_copy(bssid->MacAddress, hdr->addr2); + bssid->Privacy = 1; + return _SUCCESS; + } + + memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval23a_from_ie(bssid->IEs), 2); + bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod); + + val16 = rtw_get_capability23a(bssid); + + if (val16 & BIT(0)) { + bssid->InfrastructureMode = Ndis802_11Infrastructure; + ether_addr_copy(bssid->MacAddress, hdr->addr2); + } else { + bssid->InfrastructureMode = Ndis802_11IBSS; + ether_addr_copy(bssid->MacAddress, hdr->addr3); + } + + if (val16 & BIT(4)) + bssid->Privacy = 1; + else + bssid->Privacy = 0; + + bssid->Configuration.ATIMWindow = 0; + + /* 20/40 BSS Coexistence check */ + if ((pregistrypriv->wifi_spec == 1) && (false == pmlmeinfo->bwmode_updated)) + { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); + if (p && len > 0) { + struct HT_caps_element *pHT_caps; + pHT_caps = (struct HT_caps_element *)(p + 2); + + if (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14)) + pmlmepriv->num_FortyMHzIntolerant++; + } else + { + pmlmepriv->num_sta_no_ht++; + } + } + + + /* mark bss info receving from nearby channel as SignalQuality 101 */ + if (bssid->Configuration.DSConfig != rtw_get_oper_ch23a(padapter)) + bssid->PhyInfo.SignalQuality = 101; + + return _SUCCESS; +} + +void start_create_ibss23a(struct rtw_adapter* padapter) +{ + unsigned short caps; + u8 val8; + u8 join_type; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; + pmlmeinfo->bcn_interval = get_beacon_interval23a(pnetwork); + + /* update wireless mode */ + update_wireless_mode23a(padapter); + + /* udpate capability */ + caps = rtw_get_capability23a(pnetwork); + update_capinfo23a(padapter, caps); + if (caps&cap_IBSS)/* adhoc master */ + { + val8 = 0xcf; + rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + /* switch channel */ + /* SelectChannel23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + + beacon_timing_control23a(padapter); + + /* set msr to WIFI_FW_ADHOC_STATE */ + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); + + /* issue beacon */ + if (send_beacon23a(padapter) == _FAIL) + { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); + + report_join_res23a(padapter, -1); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + } + else + { + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + report_join_res23a(padapter, 1); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + } + } + else + { + DBG_8723A("start_create_ibss23a, invalid cap:%x\n", caps); + return; + } +} + +void start_clnt_join23a(struct rtw_adapter* padapter) +{ + unsigned short caps; + u8 val8; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + int beacon_timeout; + + pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; + pmlmeinfo->bcn_interval = get_beacon_interval23a(pnetwork); + + /* update wireless mode */ + update_wireless_mode23a(padapter); + + /* udpate capability */ + caps = rtw_get_capability23a(pnetwork); + update_capinfo23a(padapter, caps); + if (caps&cap_ESS) { + /* switch channel */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + Set_MSR23a(padapter, WIFI_FW_STATION_STATE); + + val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + /* switch channel */ + /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + + /* here wait for receiving the beacon to start auth */ + /* and enable a timer */ + beacon_timeout = decide_wait_for_beacon_timeout23a(pmlmeinfo->bcn_interval); + set_link_timer(pmlmeext, beacon_timeout); + mod_timer(&padapter->mlmepriv.assoc_timer, jiffies + + msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout)); + pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; + } + else if (caps&cap_IBSS) /* adhoc client */ + { + Set_MSR23a(padapter, WIFI_FW_ADHOC_STATE); + + val8 = 0xcf; + rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + /* switch channel */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + beacon_timing_control23a(padapter); + + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + + report_join_res23a(padapter, 1); + } + else + { + /* DBG_8723A("marc: invalid cap:%x\n", caps); */ + return; + } +} + +void start_clnt_auth23a(struct rtw_adapter* padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + del_timer_sync(&pmlmeext->link_timer); + + pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); + pmlmeinfo->state |= WIFI_FW_AUTH_STATE; + + pmlmeinfo->auth_seq = 1; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeext->retry = 0; + + /* Because of AP's not receiving deauth before */ + /* AP may: 1)not response auth or 2)deauth us after link is complete */ + /* issue deauth before issuing auth to deal with the situation */ + /* Commented by Albert 2012/07/21 */ + /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ + issue_deauth23a(padapter, (&pmlmeinfo->network)->MacAddress, WLAN_REASON_DEAUTH_LEAVING); + + DBG_8723A_LEVEL(_drv_always_, "start auth\n"); + issue_auth23a(padapter, NULL, 0); + + set_link_timer(pmlmeext, REAUTH_TO); +} + +void start_clnt_assoc23a(struct rtw_adapter* padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + del_timer_sync(&pmlmeext->link_timer); + + pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); + pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); + + issue_assocreq23a(padapter); + + set_link_timer(pmlmeext, REASSOC_TO); +} + +unsigned int receive_disconnect23a(struct rtw_adapter *padapter, unsigned char *MacAddr, unsigned short reason) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* check A3 */ + if (!ether_addr_equal(MacAddr, get_my_bssid23a(&pmlmeinfo->network))) + return _SUCCESS; + + DBG_8723A("%s\n", __func__); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + { + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_del_sta_event23a(padapter, MacAddr, reason); + + } + else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) + { + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_join_res23a(padapter, -2); + } + } + + return _SUCCESS; +} + +static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *bssid) +{ + struct registry_priv *pregistrypriv; + struct mlme_ext_priv *pmlmeext; + struct rt_channel_info *chplan_new; + u8 channel; + u8 i; + + pregistrypriv = &padapter->registrypriv; + pmlmeext = &padapter->mlmeextpriv; + + /* Adjust channel plan by AP Country IE */ + if (pregistrypriv->enable80211d && + (!pmlmeext->update_channel_plan_by_ap_done)) + { + u8 *ie, *p; + u32 len; + struct rt_channel_plan chplan_ap; + struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; + u8 country[4]; + u8 fcn; /* first channel number */ + u8 noc; /* number of channel */ + u8 j, k; + + ie = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (!ie) return; + if (len < 6) return; + + ie += 2; + p = ie; + ie += len; + + memset(country, 0, 4); + memcpy(country, p, 3); + p += 3; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("%s: 802.11d country =%s\n", __func__, country)); + + i = 0; + while ((ie - p) >= 3) + { + fcn = *(p++); + noc = *(p++); + p++; + + for (j = 0; j < noc; j++) + { + if (fcn <= 14) channel = fcn + j; /* 2.4 GHz */ + else channel = fcn + j*4; /* 5 GHz */ + + chplan_ap.Channel[i++] = channel; + } + } + chplan_ap.Len = i; + + memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); + memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); + chplan_new = pmlmeext->channel_set; + + i = j = k = 0; + if (pregistrypriv->wireless_mode & WIRELESS_11G) { + do { + if ((i == MAX_CHANNEL_NUM) || + (chplan_sta[i].ChannelNum == 0) || + (chplan_sta[i].ChannelNum > 14)) + break; + + if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) + break; + + if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + i++; + j++; + k++; + } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } while (1); + + /* change AP not support channel to Passive scan */ + while ((i < MAX_CHANNEL_NUM) && + (chplan_sta[i].ChannelNum != 0) && + (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } + + /* add channel AP supported */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } else { + /* keep original STA 2.4G channel plan */ + while ((i < MAX_CHANNEL_NUM) && + (chplan_sta[i].ChannelNum != 0) && + (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } + + /* skip AP 2.4G channel plan */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + j++; + } + } + + if (pregistrypriv->wireless_mode & WIRELESS_11A) { + do { + if ((i == MAX_CHANNEL_NUM) || + (chplan_sta[i].ChannelNum == 0)) + break; + + if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0)) + break; + + if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) + { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + i++; + j++; + k++; + } + else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) + { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; +/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */ + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } + else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) + { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } while (1); + + /* change AP not support channel to Passive scan */ + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = SCAN_PASSIVE; + i++; + k++; + } + + /* add channel AP supported */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } else { + /* keep original STA 5G channel plan */ + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } + } + pmlmeext->update_channel_plan_by_ap_done = 1; + } + + /* If channel is used by AP, set channel scan type to active */ + channel = bssid->Configuration.DSConfig; + chplan_new = pmlmeext->channel_set; + i = 0; + while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { + if (chplan_new[i].ChannelNum == channel) + { + if (chplan_new[i].ScanType == SCAN_PASSIVE) { + /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */ + if (channel >= 52 && channel <= 144) + break; + + chplan_new[i].ScanType = SCAN_ACTIVE; + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, + ("%s: change channel %d scan type from passive to active\n", + __func__, channel)); + } + break; + } + i++; + } +} + +/**************************************************************************** + +Following are the functions to report events + +*****************************************************************************/ + +void report_survey_event23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct survey_event *psurvey_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext; + struct cmd_priv *pcmdpriv; + + if (!padapter) + return; + + pmlmeext = &padapter->mlmeextpriv; + pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!pcmd_obj) + return; + + cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); + if (!pevtcmd) { + kfree(pcmd_obj); + return; + } + + INIT_LIST_HEAD(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct survey_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); + pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + psurvey_evt = (struct survey_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); + + if (collect_bss_info23a(padapter, precv_frame, &psurvey_evt->bss) == _FAIL) { + kfree(pcmd_obj); + kfree(pevtcmd); + return; + } + + process_80211d(padapter, &psurvey_evt->bss); + + rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj); + + pmlmeext->sitesurvey_res.bss_cnt++; + + return; +} + +void report_surveydone_event23a(struct rtw_adapter *padapter) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct surveydone_event *psurveydone_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!pcmd_obj) + return; + + cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); + if (!pevtcmd) { + kfree(pcmd_obj); + return; + } + + INIT_LIST_HEAD(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct surveydone_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); + pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + psurveydone_evt = (struct surveydone_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); + psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; + + DBG_8723A("survey done event(%x)\n", psurveydone_evt->bss_cnt); + + rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj); + + return; +} + +void report_join_res23a(struct rtw_adapter *padapter, int res) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct joinbss_event *pjoinbss_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!pcmd_obj) + return; + + cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); + if (!pevtcmd) { + kfree(pcmd_obj); + return; + } + + INIT_LIST_HEAD(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct joinbss_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); + pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + pjoinbss_evt = (struct joinbss_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); + memcpy((unsigned char *)&pjoinbss_evt->network.network, + &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); + pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; + + DBG_8723A("report_join_res23a(%d)\n", res); + + rtw_joinbss_event_prehandle23a(padapter, (u8 *)&pjoinbss_evt->network); + + rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj); + + return; +} + +void report_del_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAddr, unsigned short reason) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct sta_info *psta; + int mac_id; + struct stadel_event *pdel_sta_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!pcmd_obj) + return; + + cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); + if (!pevtcmd) { + kfree(pcmd_obj); + return; + } + + INIT_LIST_HEAD(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stadel_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); + pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + pdel_sta_evt = (struct stadel_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); + ether_addr_copy((unsigned char *)&pdel_sta_evt->macaddr, MacAddr); + memcpy((unsigned char *)pdel_sta_evt->rsvd, (unsigned char *)&reason, + 2); + + psta = rtw_get_stainfo23a(&padapter->stapriv, MacAddr); + if (psta) + mac_id = (int)psta->mac_id; + else + mac_id = (-1); + + pdel_sta_evt->mac_id = mac_id; + + DBG_8723A("report_del_sta_event23a: delete STA, mac_id =%d\n", mac_id); + + rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj); + + return; +} + +void report_add_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAddr, int cam_idx) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct stassoc_event *padd_sta_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!pcmd_obj) + return; + + cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); + if (!pevtcmd) { + kfree(pcmd_obj); + return; + } + + INIT_LIST_HEAD(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stassoc_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); + pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + padd_sta_evt = (struct stassoc_event*)(pevtcmd + sizeof(struct C2HEvent_Header)); + ether_addr_copy((unsigned char *)&padd_sta_evt->macaddr, MacAddr); + padd_sta_evt->cam_id = cam_idx; + + DBG_8723A("report_add_sta_event23a: add STA\n"); + + rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj); + + return; +} + +/**************************************************************************** + +Following are the event callback functions + +*****************************************************************************/ + +/* for sta/adhoc mode */ +void update_sta_info23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* ERP */ + VCS_update23a(padapter, psta); + + /* HT */ + if (pmlmepriv->htpriv.ht_option) + { + psta->htpriv.ht_option = true; + + psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; + + if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps)) + psta->htpriv.sgi = true; + + psta->qos_option = true; + + } + else + { + psta->htpriv.ht_option = false; + + psta->htpriv.ampdu_enable = false; + + psta->htpriv.sgi = false; + psta->qos_option = false; + + } + psta->htpriv.bwmode = pmlmeext->cur_bwmode; + psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; + + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ + + /* QoS */ + if (pmlmepriv->qospriv.qos_option) + psta->qos_option = true; + + psta->state = _FW_LINKED; +} + +void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_res) +{ + struct sta_info *psta, *psta_bmc; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 join_type; + u16 media_status; + + if (join_res < 0) + { + join_type = 1; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + + /* restore to initial setting. */ + update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); + + goto exit_mlmeext_joinbss_event_callback23a; + } + + if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) + { + /* for bc/mc */ + psta_bmc = rtw_get_bcmc_stainfo23a(padapter); + if (psta_bmc) + { + pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc; + update_bmc_sta_support_rate23a(padapter, psta_bmc->mac_id); + Update_RA_Entry23a(padapter, psta_bmc); + } + } + + /* turn on dynamic functions */ + Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); + + /* update IOT-releated issue */ + update_IOT_info23a(padapter); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); + + /* BCN interval */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); + + /* udpate capability */ + update_capinfo23a(padapter, pmlmeinfo->capability); + + /* WMM, Update EDCA param */ + WMMOnAssocRsp23a(padapter); + + /* HT */ + HTOnAssocRsp23a(padapter); + + /* Set cur_channel&cur_bwmode&cur_ch_offset */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress); + if (psta) /* only for infra. mode */ + { + pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; + + /* DBG_8723A("set_sta_rate23a\n"); */ + + psta->wireless_mode = pmlmeext->cur_wireless_mode; + + /* set per sta rate after updating HT cap. */ + set_sta_rate23a(padapter, psta); + + media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE: 1 means connect */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); + } + + join_type = 2; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + { + /* correcting TSF */ + correct_TSF23a(padapter, pmlmeext); + + /* set_link_timer(pmlmeext, DISCONNECT_TO); */ + } + + rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_CONNECT, 0); + +exit_mlmeext_joinbss_event_callback23a: + DBG_8723A("=>%s\n", __func__); +} + +void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 join_type; + + DBG_8723A("%s\n", __func__); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) + { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)/* adhoc master or sta_count>1 */ + { + /* nothing to do */ + } + else/* adhoc client */ + { + /* update TSF Value */ + /* update_TSF23a(pmlmeext, pframe, len); */ + + /* correcting TSF */ + correct_TSF23a(padapter, pmlmeext); + + /* start beacon */ + if (send_beacon23a(padapter) == _FAIL) + { + pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; + + pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; + + return; + } + + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + + } + + join_type = 2; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + } + + pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; + + /* rate radaptive */ + Update_RA_Entry23a(padapter, psta); + + /* update adhoc sta_info */ + update_sta_info23a(padapter, psta); +} + +void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (is_client_associated_to_ap23a(padapter) || is_IBSS_empty23a(padapter)) + { + /* set_opmode_cmd(padapter, infra_client_with_mlme); */ + + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + + /* restore to initial setting. */ + update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); + + /* switch to the 20M Hz mode after disconnect */ + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + /* SelectChannel23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */ + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + flush_all_cam_entry23a(padapter); + + pmlmeinfo->state = WIFI_FW_NULL_STATE; + + /* set MSR to no link state -> infra. mode */ + Set_MSR23a(padapter, _HW_STATE_STATION_); + + del_timer_sync(&pmlmeext->link_timer); + } +} + +/**************************************************************************** + +Following are the functions for the timer handlers + +*****************************************************************************/ +void linked23a_rx_sig_stren_disp(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 mac_id; + int UndecoratedSmoothedPWDB; + if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) + mac_id = 0; + else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) + mac_id = 2; + + rtw_hal_get_def_var23a(padapter, HW_DEF_RA_INFO_DUMP,&mac_id); + + rtw_hal_get_def_var23a(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); + DBG_8723A("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB); +} + +static u8 chk_ap_is_alive(struct rtw_adapter *padapter, struct sta_info *psta) +{ + u8 ret = false; + + if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) && + sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) && + sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta)) + ret = false; + else + ret = true; + + sta_update_last_rx_pkts(psta); + return ret; +} + +void linked_status_chk23a(struct rtw_adapter *padapter) +{ + u32 i; + struct sta_info *psta; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct sta_priv *pstapriv = &padapter->stapriv; + + if (padapter->bRxRSSIDisplay) + linked23a_rx_sig_stren_disp(padapter); + + rtw_hal_sreset_linked_status_check23a(padapter); + + if (is_client_associated_to_ap23a(padapter)) + { + /* linked infrastructure client mode */ + + int tx_chk = _SUCCESS, rx_chk = _SUCCESS; + int rx_chk_limit; + + rx_chk_limit = 4; + + if ((psta = rtw_get_stainfo23a(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) + { + bool is_p2p_enable = false; +#ifdef CONFIG_8723AU_P2P + is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); +#endif + + if (chk_ap_is_alive(padapter, psta) == false) + rx_chk = _FAIL; + + if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) + tx_chk = _FAIL; + + if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) { + u8 backup_oper_channel = 0; + + /* switch to correct channel of current network before issue keep-alive frames */ + if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel) { + backup_oper_channel = rtw_get_oper_ch23a(padapter); + SelectChannel23a(padapter, pmlmeext->cur_channel); + } + + if (rx_chk != _SUCCESS) + issue_probereq23a_ex23a(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1); + + if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) { + tx_chk = issue_nulldata23a(padapter, psta->hwaddr, 0, 3, 1); + /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */ + if (tx_chk == _SUCCESS && !is_p2p_enable) + rx_chk = _SUCCESS; + } + + /* back to the original operation channel */ + if (backup_oper_channel>0) + SelectChannel23a(padapter, backup_oper_channel); + + } else { + if (rx_chk != _SUCCESS) { + if (pmlmeext->retry == 0) { + issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); + issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); + issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); + } + } + + if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) + tx_chk = issue_nulldata23a(padapter, NULL, 0, 1, 0); + } + + if (rx_chk == _FAIL) { + pmlmeext->retry++; + if (pmlmeext->retry > rx_chk_limit) { + DBG_8723A_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", + FUNC_ADPT_ARG(padapter)); + receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, + WLAN_REASON_EXPIRATION_CHK); + return; + } + } else { + pmlmeext->retry = 0; + } + + if (tx_chk == _FAIL) { + pmlmeinfo->link_count &= 0xf; + } else { + pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; + pmlmeinfo->link_count = 0; + } + + } /* end of if ((psta = rtw_get_stainfo23a(pstapriv, passoc_res->network.MacAddress)) != NULL) */ + } + else if (is_client_associated_to_ibss23a(padapter)) + { + /* linked IBSS mode */ + /* for each assoc list entry to check the rx pkt counter */ + for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) + { + if (pmlmeinfo->FW_sta_info[i].status == 1) + { + psta = pmlmeinfo->FW_sta_info[i].psta; + + if (NULL == psta) continue; + + if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) + { + + if (pmlmeinfo->FW_sta_info[i].retry<3) + { + pmlmeinfo->FW_sta_info[i].retry++; + } + else + { + pmlmeinfo->FW_sta_info[i].retry = 0; + pmlmeinfo->FW_sta_info[i].status = 0; + report_del_sta_event23a(padapter, psta->hwaddr, + 65535/* indicate disconnect caused by no rx */ + ); + } + } + else + { + pmlmeinfo->FW_sta_info[i].retry = 0; + pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); + } + } + } + + /* set_link_timer(pmlmeext, DISCONNECT_TO); */ + + } +} + +static void survey_timer_hdl(unsigned long data) +{ + struct rtw_adapter *padapter = (struct rtw_adapter *)data; + struct cmd_obj *ph2c; + struct sitesurvey_parm *psurveyPara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + + /* issue rtw_sitesurvey_cmd23a */ + if (pmlmeext->sitesurvey_res.state > SCAN_START) { + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) + pmlmeext->sitesurvey_res.channel_idx++; + + if (pmlmeext->scan_abort == true) + { +#ifdef CONFIG_8723AU_P2P + if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) + { + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); + pmlmeext->sitesurvey_res.channel_idx = 3; + DBG_8723A("%s idx:%d, cnt:%u\n", __func__, + pmlmeext->sitesurvey_res.channel_idx, + pwdinfo->find_phase_state_exchange_cnt); + } else + #endif + { + pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; + DBG_8723A("%s idx:%d\n", __func__, + pmlmeext->sitesurvey_res.channel_idx); + } + + pmlmeext->scan_abort = false;/* reset */ + } + + ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!ph2c) + goto exit_survey_timer_hdl; + + psurveyPara = (struct sitesurvey_parm*) + kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); + if (!psurveyPara) { + kfree(ph2c); + goto exit_survey_timer_hdl; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); + rtw_enqueue_cmd23a(pcmdpriv, ph2c); + } + +exit_survey_timer_hdl: + return; +} + +static void link_timer_hdl(unsigned long data) +{ + struct rtw_adapter *padapter = (struct rtw_adapter *)data; + /* static unsigned int rx_pkt = 0; */ + /* static u64 tx_cnt = 0; */ + /* struct xmit_priv *pxmitpriv = &padapter->xmitpriv; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + /* struct sta_priv *pstapriv = &padapter->stapriv; */ + + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) + { + DBG_8723A("link_timer_hdl:no beacon while connecting\n"); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_join_res23a(padapter, -3); + } + else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) + { + /* re-auth timer */ + if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) + { + /* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */ + /* */ + pmlmeinfo->state = 0; + report_join_res23a(padapter, -1); + return; + /* */ + /* else */ + /* */ + /* pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */ + /* pmlmeinfo->reauth_count = 0; */ + /* */ + } + + DBG_8723A("link_timer_hdl: auth timeout and try again\n"); + pmlmeinfo->auth_seq = 1; + issue_auth23a(padapter, NULL, 0); + set_link_timer(pmlmeext, REAUTH_TO); + } + else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) + { + /* re-assoc timer */ + if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) + { + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_join_res23a(padapter, -2); + return; + } + + DBG_8723A("link_timer_hdl: assoc timeout and try again\n"); + issue_assocreq23a(padapter); + set_link_timer(pmlmeext, REASSOC_TO); + } + + return; +} + +static void addba_timer_hdl(unsigned long data) +{ + struct sta_info *psta = (struct sta_info *)data; + struct ht_priv *phtpriv; + + if (!psta) + return; + + phtpriv = &psta->htpriv; + + if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true)) + { + if (phtpriv->candidate_tid_bitmap) + phtpriv->candidate_tid_bitmap = 0x0; + + } +} + +void init_addba_retry_timer23a(struct sta_info *psta) +{ + setup_timer(&psta->addba_retry_timer, addba_timer_hdl, + (unsigned long)psta); +} + +void init_mlme_ext_timer23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + setup_timer(&pmlmeext->survey_timer, survey_timer_hdl, + (unsigned long)padapter); + + setup_timer(&pmlmeext->link_timer, link_timer_hdl, + (unsigned long)padapter); +} + +u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + return H2C_SUCCESS; +} + +u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + u8 type; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; + + if (psetop->mode == Ndis802_11APMode) + { + pmlmeinfo->state = WIFI_FW_AP_STATE; + type = _HW_STATE_AP_; + } + else if (psetop->mode == Ndis802_11Infrastructure) + { + pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */ + pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ + type = _HW_STATE_STATION_; + } + else if (psetop->mode == Ndis802_11IBSS) + { + type = _HW_STATE_ADHOC_; + } + else + { + type = _HW_STATE_NOLINK_; + } + + rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); + /* Set_NETYPE0_MSR(padapter, type); */ + + return H2C_SUCCESS; +} + +u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; + /* u32 initialgain; */ + + if (pparm->InfrastructureMode == Ndis802_11APMode) { +#ifdef CONFIG_8723AU_AP_MODE + + if (pmlmeinfo->state == WIFI_FW_AP_STATE) + { + /* todo: */ + return H2C_SUCCESS; + } +#endif + } + + /* below is for ad-hoc master */ + if (pparm->InfrastructureMode == Ndis802_11IBSS) { + rtw_joinbss_reset23a(padapter); + + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pmlmeinfo->ERP_enable = 0; + pmlmeinfo->WMM_enable = 0; + pmlmeinfo->HT_enable = 0; + pmlmeinfo->HT_caps_enable = 0; + pmlmeinfo->HT_info_enable = 0; + pmlmeinfo->agg_enable_bitmap = 0; + pmlmeinfo->candidate_tid_bitmap = 0; + + /* disable dynamic functions, such as high power, DIG */ + Save_DM_Func_Flag23a(padapter); + Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); + + /* config the initial gain under linking, need to write the BB registers */ + /* initialgain = 0x1E; */ + /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ + + /* cancel link timer */ + del_timer_sync(&pmlmeext->link_timer); + + /* clear CAM */ + flush_all_cam_entry23a(padapter); + + if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ + return H2C_PARAMETERS_ERROR; + + memcpy(pnetwork, pparm, sizeof(struct wlan_bssid_ex)); + + start_create_ibss23a(padapter); + } + + return H2C_SUCCESS; +} + +u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + u8 join_type; + struct ndis_802_11_var_ies * pIE; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf; + struct HT_info_element *pht_info; + u32 i; + /* u32 initialgain; */ + /* u32 acparm; */ + + /* check already connecting to AP or not */ + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + { + if (pmlmeinfo->state & WIFI_FW_STATION_STATE) + issue_deauth23a_ex23a(padapter, pnetwork->MacAddress, + WLAN_REASON_DEAUTH_LEAVING, 5, 100); + + pmlmeinfo->state = WIFI_FW_NULL_STATE; + + /* clear CAM */ + flush_all_cam_entry23a(padapter); + + del_timer_sync(&pmlmeext->link_timer); + + /* set MSR to nolink -> infra. mode */ + /* Set_MSR23a(padapter, _HW_STATE_NOLINK_); */ + Set_MSR23a(padapter, _HW_STATE_STATION_); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); + } + + rtw_joinbss_reset23a(padapter); + + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pmlmeinfo->ERP_enable = 0; + pmlmeinfo->WMM_enable = 0; + pmlmeinfo->HT_enable = 0; + pmlmeinfo->HT_caps_enable = 0; + pmlmeinfo->HT_info_enable = 0; + pmlmeinfo->agg_enable_bitmap = 0; + pmlmeinfo->candidate_tid_bitmap = 0; + pmlmeinfo->bwmode_updated = false; + /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */ + + if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ + return H2C_PARAMETERS_ERROR; + + memcpy(pnetwork, pbuf, sizeof(struct wlan_bssid_ex)); + + /* Check AP vendor to move rtw_joinbss_cmd23a() */ + /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pnetwork->IEs, + pnetwork->IELength); */ + + for (i = sizeof(struct ndis_802_11_fixed_ies); i < pnetwork->IELength;) + { + pIE = (struct ndis_802_11_var_ies *)(pnetwork->IEs + i); + + switch (pIE->ElementID) + { + case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */ + if (!memcmp(pIE->data, WMM_OUI23A, 4)) + pmlmeinfo->WMM_enable = 1; + break; + + case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ + pmlmeinfo->HT_caps_enable = 1; + break; + + case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ + pmlmeinfo->HT_info_enable = 1; + + /* spec case only for cisco's ap because cisco's ap + * issue assoc rsp using mcs rate @40MHz or @20MHz */ + pht_info = (struct HT_info_element *)(pIE->data); + + if ((pregpriv->cbw40_enable) && + (pht_info->infos[0] & BIT(2))) { + /* switch to the 40M Hz mode according to AP */ + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; + switch (pht_info->infos[0] & 0x3) + { + case 1: + pmlmeext->cur_ch_offset = + HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case 3: + pmlmeext->cur_ch_offset = + HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + pmlmeext->cur_ch_offset = + HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + + DBG_8723A("set ch/bw before connected\n"); + } + break; + + default: + break; + } + + i += (pIE->Length + 2); + } + /* disable dynamic functions, such as high power, DIG */ + /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */ + + /* config the initial gain under linking, need to write the BB + registers */ + /* initialgain = 0x1E; */ + /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, + (u8 *)(&initialgain)); */ + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, + pmlmeinfo->network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + /* cancel link timer */ + del_timer_sync(&pmlmeext->link_timer); + + start_clnt_join23a(padapter); + + return H2C_SUCCESS; +} + +u8 disconnect_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct disconnect_parm *param = (struct disconnect_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; + u8 val8; + + if (is_client_associated_to_ap23a(padapter)) + { + issue_deauth23a_ex23a(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100); + } + + /* set_opmode_cmd(padapter, infra_client_with_mlme); */ + + /* pmlmeinfo->state = WIFI_FW_NULL_STATE; */ + + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL); + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr); + + /* restore to initial setting. */ + update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); + + if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) + { + /* Stop BCN */ + val8 = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); + } + + /* set MSR to no link state -> infra. mode */ + Set_MSR23a(padapter, _HW_STATE_STATION_); + + pmlmeinfo->state = WIFI_FW_NULL_STATE; + + /* switch to the 20M Hz mode after disconnect */ + pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + flush_all_cam_entry23a(padapter); + + del_timer_sync(&pmlmeext->link_timer); + + rtw_free_uc_swdec_pending_queue23a(padapter); + + return H2C_SUCCESS; +} + +static int rtw_scan_ch_decision(struct rtw_adapter *padapter, struct rtw_ieee80211_channel *out, + u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) +{ + int i, j; + int scan_ch_num = 0; + int set_idx; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + /* clear out first */ + memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num); + + /* acquire channels from in */ + j = 0; + for (i = 0;ichannel_set, in[i].hw_value)) >= 0 + ) + { + memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); + + if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) + out[j].flags &= IEEE80211_CHAN_NO_IR; + + j++; + } + if (j>= out_num) + break; + } + + /* if out is empty, use channel_set as default */ + if (j == 0) { + for (i = 0;imax_chan_nums;i++) { + out[i].hw_value = pmlmeext->channel_set[i].ChannelNum; + + if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) + out[i].flags &= IEEE80211_CHAN_NO_IR; + + j++; + } + } + + if (padapter->setband == GHZ_24) { /* 2.4G */ + for (i = 0; i < j ; i++) { + if (out[i].hw_value > 35) + memset(&out[i], 0, + sizeof(struct rtw_ieee80211_channel)); + else + scan_ch_num++; + } + j = scan_ch_num; + } else if (padapter->setband == GHZ_50) { /* 5G */ + for (i = 0; i < j ; i++) { + if (out[i].hw_value > 35) { + memcpy(&out[scan_ch_num++], &out[i], sizeof(struct rtw_ieee80211_channel)); + } + } + j = scan_ch_num; + } else + {} + + return j; +} + +u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; + u8 bdelayscan = false; + u8 val8; + u32 initialgain; + u32 i; + + if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) { + /* for first time sitesurvey_cmd */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_TXBUF, NULL); + + pmlmeext->sitesurvey_res.state = SCAN_START; + pmlmeext->sitesurvey_res.bss_cnt = 0; + pmlmeext->sitesurvey_res.channel_idx = 0; + + for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { + if (pparm->ssid[i].ssid_len) { + memcpy(pmlmeext->sitesurvey_res.ssid[i].ssid, + pparm->ssid[i].ssid, IW_ESSID_MAX_SIZE); + pmlmeext->sitesurvey_res.ssid[i].ssid_len = + pparm->ssid[i].ssid_len; + } else { + pmlmeext->sitesurvey_res.ssid[i].ssid_len = 0; + } + } + + pmlmeext->sitesurvey_res.ch_num = + rtw_scan_ch_decision(padapter, + pmlmeext->sitesurvey_res.ch, + RTW_CHANNEL_SCAN_AMOUNT, + pparm->ch, pparm->ch_num); + + pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; + + /* issue null data if associating to the AP */ + if (is_client_associated_to_ap23a(padapter)) { + pmlmeext->sitesurvey_res.state = SCAN_TXNULL; + + /* switch to correct channel of current network + before issue keep-alive frames */ + if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel) + SelectChannel23a(padapter, pmlmeext->cur_channel); + + issue_nulldata23a(padapter, NULL, 1, 3, 500); + + bdelayscan = true; + } + + if (bdelayscan) { + /* delay 50ms to protect nulldata(1). */ + set_survey_timer(pmlmeext, 50); + return H2C_SUCCESS; + } + } + + if ((pmlmeext->sitesurvey_res.state == SCAN_START) || + (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { + /* disable dynamic functions, such as high power, DIG */ + Save_DM_Func_Flag23a(padapter); + Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); + + /* config the initial gain under scaning, need to + write the BB registers */ + if ((wdev_to_priv(padapter->rtw_wdev))->p2p_enabled == true) { + initialgain = 0x30; + } else + initialgain = 0x1E; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, + (u8 *)(&initialgain)); + + /* set MSR to no link state */ + Set_MSR23a(padapter, _HW_STATE_NOLINK_); + + val8 = 1; /* under site survey */ + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, + (u8 *)(&val8)); + + pmlmeext->sitesurvey_res.state = SCAN_PROCESS; + } + + site_survey23a(padapter); + + return H2C_SUCCESS; +} + +u8 setauth_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct setauth_parm *pparm = (struct setauth_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pparm->mode < 4) + { + pmlmeinfo->auth_algo = pparm->mode; + } + + return H2C_SUCCESS; +} + +u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + unsigned short ctrl; + struct setkey_parm *pparm = (struct setkey_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + /* main tx key for wep. */ + if (pparm->set_tx) + pmlmeinfo->key_index = pparm->keyid; + + /* write cam */ + ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; + + DBG_8723A_LEVEL(_drv_always_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) " + "keyid:%d\n", pparm->algorithm, pparm->keyid); + write_cam23a(padapter, pparm->keyid, ctrl, null_sta, pparm->key); + + /* allow multicast packets to driver */ + padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); + + return H2C_SUCCESS; +} + +u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + u16 ctrl = 0; + u8 cam_id;/* cam_entry */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; + + /* cam_entry: */ + /* 0~3 for default key */ + + /* for concurrent mode (ap+sta): */ + /* default key is disable, using sw encrypt/decrypt */ + /* cam_entry = 4 for sta mode (macid = 0) */ + /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */ + + /* for concurrent mode (sta+sta): */ + /* default key is disable, using sw encrypt/decrypt */ + /* cam_entry = 4 mapping to macid = 0 */ + /* cam_entry = 5 mapping to macid = 2 */ + + cam_id = 4; + + DBG_8723A_LEVEL(_drv_always_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n", + pparm->algorithm, cam_id); + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) + { + + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + if (pparm->algorithm == _NO_PRIVACY_) /* clear cam entry */ + { + clear_cam_entry23a(padapter, pparm->id); + return H2C_SUCCESS_RSP; + } + + psta = rtw_get_stainfo23a(pstapriv, pparm->addr); + if (psta) + { + ctrl = (BIT(15) | ((pparm->algorithm) << 2)); + + DBG_8723A("r871x_set_stakey_hdl23a(): enc_algorithm =%d\n", pparm->algorithm); + + if ((psta->mac_id<1) || (psta->mac_id>(NUM_STA-4))) + { + DBG_8723A("r871x_set_stakey_hdl23a():set_stakey failed, mac_id(aid) =%d\n", psta->mac_id); + return H2C_REJECTED; + } + + cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ + + DBG_8723A("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry =%d\n", pparm->addr[0], + pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4], + pparm->addr[5], cam_id); + + write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key); + + return H2C_SUCCESS_RSP; + + } + else + { + DBG_8723A("r871x_set_stakey_hdl23a(): sta has been free\n"); + return H2C_REJECTED; + } + + } + + /* below for sta mode */ + + if (pparm->algorithm == _NO_PRIVACY_) /* clear cam entry */ + { + clear_cam_entry23a(padapter, pparm->id); + return H2C_SUCCESS; + } + + ctrl = BIT(15) | ((pparm->algorithm) << 2); + + write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key); + + pmlmeinfo->enc_algo = pparm->algorithm; + + return H2C_SUCCESS; +} + +u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + struct sta_info *psta = rtw_get_stainfo23a(&padapter->stapriv, pparm->addr); + + if (!psta) + return H2C_SUCCESS; + + if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && + (pmlmeinfo->HT_enable)) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + issue_action_BA23a(padapter, pparm->addr, + WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); + mod_timer(&psta->addba_retry_timer, + jiffies + msecs_to_jiffies(ADDBA_TO)); + } else { + psta->htpriv.candidate_tid_bitmap &= ~CHKBIT(pparm->tid); + } + return H2C_SUCCESS; +} + +u8 set_tx_beacon_cmd23a(struct rtw_adapter* padapter) +{ + struct cmd_obj *ph2c; + struct Tx_Beacon_param *ptxBeacon_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 res = _SUCCESS; + int len_diff = 0; + + + + ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + ptxBeacon_parm = (struct Tx_Beacon_param *) + kzalloc(sizeof(struct Tx_Beacon_param), GFP_ATOMIC); + if (!ptxBeacon_parm) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + memcpy(&ptxBeacon_parm->network, &pmlmeinfo->network, + sizeof(struct wlan_bssid_ex)); + + len_diff = update_hidden_ssid( + ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_, + ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_, + pmlmeinfo->hidden_ssid_mode); + ptxBeacon_parm->network.IELength += len_diff; + + init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + +exit: + + + + return res; +} + +u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + u8 evt_code, evt_seq; + u16 evt_sz; + uint *peventbuf; + void (*event_callback)(struct rtw_adapter *dev, u8 *pbuf); + struct evt_priv *pevt_priv = &padapter->evtpriv; + + peventbuf = (uint*)pbuf; + evt_sz = (u16)(*peventbuf&0xffff); + evt_seq = (u8)((*peventbuf>>24)&0x7f); + evt_code = (u8)((*peventbuf>>16)&0xff); + + /* checking if event code is valid */ + if (evt_code >= MAX_C2HEVT) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code)); + goto _abort_event_; + } + + /* checking if event size match the event parm size */ + if ((wlanevents[evt_code].parmsize != 0) && + (wlanevents[evt_code].parmsize != evt_sz)) { + RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n", + evt_code, wlanevents[evt_code].parmsize, evt_sz)); + goto _abort_event_; + } + + atomic_inc(&pevt_priv->event_seq); + + peventbuf += 2; + + if (peventbuf) { + event_callback = wlanevents[evt_code].event_callback; + event_callback(padapter, (u8*)peventbuf); + + pevt_priv->evt_done_cnt++; + } + +_abort_event_: + + return H2C_SUCCESS; +} + +u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + return H2C_SUCCESS; +} + +u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + if (send_beacon23a(padapter) == _FAIL) + { + DBG_8723A("issue_beacon23a, fail!\n"); + return H2C_PARAMETERS_ERROR; + } +#ifdef CONFIG_8723AU_AP_MODE + else /* tx bc/mc frames after update TIM */ + { + struct sta_info *psta_bmc; + struct list_head *plist, *phead, *ptmp; + struct xmit_frame *pxmitframe; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* for BC/MC Frames */ + psta_bmc = rtw_get_bcmc_stainfo23a(padapter); + if (!psta_bmc) + return H2C_SUCCESS; + + if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len>0)) + { + msleep(10);/* 10ms, ATIM(HIQ) Windows */ + /* spin_lock_bh(&psta_bmc->sleep_q.lock); */ + spin_lock_bh(&pxmitpriv->lock); + + phead = get_list_head(&psta_bmc->sleep_q); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, + struct xmit_frame, + list); + + list_del_init(&pxmitframe->list); + + psta_bmc->sleepq_len--; + if (psta_bmc->sleepq_len>0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + + pxmitframe->attrib.qsel = 0x11;/* HIQ */ + + rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe); + } + + /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */ + spin_unlock_bh(&pxmitpriv->lock); + } + + } +#endif + + return H2C_SUCCESS; +} + +u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf) +{ + struct set_ch_parm *set_ch_parm; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + set_ch_parm = (struct set_ch_parm *)pbuf; + + DBG_8723A(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), + set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); + + pmlmeext->cur_channel = set_ch_parm->ch; + pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; + pmlmeext->cur_bwmode = set_ch_parm->bw; + + set_channel_bwmode23a(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); + + return H2C_SUCCESS; +} + +u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct SetChannelPlan_param *setChannelPlan_param; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; + + pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); + init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); + + return H2C_SUCCESS; +} + +u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + struct LedBlink_param *ledBlink_param; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + ledBlink_param = (struct LedBlink_param *)pbuf; + + return H2C_SUCCESS; +} + +u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + return H2C_REJECTED; +} + +/* TDLS_WRCR : write RCR DATA BIT */ +/* TDLS_SD_PTI : issue peer traffic indication */ +/* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */ +/* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */ +/* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */ +/* TDLS_OFF_CH : first time set channel to off channel */ +/* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */ +/* TDLS_P_OFF_CH : periodically go to off channel */ +/* TDLS_P_BASE_CH : periodically go back to base channel */ +/* TDLS_RS_RCR : restore RCR */ +/* TDLS_CKALV_PH1 : check alive timer phase1 */ +/* TDLS_CKALV_PH2 : check alive timer phase2 */ +/* TDLS_FREE_STA : free tdls sta */ +u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) +{ + return H2C_REJECTED; +} diff --git a/drivers/staging/rtl8723au/core/rtw_p2p.c b/drivers/staging/rtl8723au/core/rtw_p2p.c new file mode 100644 index 000000000000..becc3feaca1d --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_p2p.c @@ -0,0 +1,3963 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_P2P_C_ + +#include +#include +#include + +#ifdef CONFIG_8723AU_P2P + +static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8* ch_list, u8 ch_cnt) +{ + int found = 0, i = 0; + + for (i = 0; i < ch_cnt; i++) + { + if (ch_list[ i ] == desired_ch) + { + found = 1; + break; + } + } + return found; +} + +static int is_any_client_associated(struct rtw_adapter *padapter) +{ + return padapter->stapriv.asoc_list_cnt ? true : false; +} + +static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + struct list_head *phead, *plist; + u32 len = 0; + u16 attr_len = 0; + u8 tmplen, *pdata_attr, *pstart, *pcur; + struct sta_info *psta; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct sta_priv *pstapriv = &padapter->stapriv; + + DBG_8723A("%s\n", __func__); + + pdata_attr = kzalloc(MAX_P2P_IE_LEN, GFP_ATOMIC); + + pstart = pdata_attr; + pcur = pdata_attr; + + spin_lock_bh(&pstapriv->asoc_list_lock); + phead = &pstapriv->asoc_list; + + list_for_each(plist, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + if (psta->is_p2p_device) + { + tmplen = 0; + + pcur++; + + /* P2P device address */ + memcpy(pcur, psta->dev_addr, ETH_ALEN); + pcur += ETH_ALEN; + + /* P2P interface address */ + memcpy(pcur, psta->hwaddr, ETH_ALEN); + pcur += ETH_ALEN; + + *pcur = psta->dev_cap; + pcur++; + + /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */ + RTW_PUT_BE16(pcur, psta->config_methods); + pcur += 2; + + memcpy(pcur, psta->primary_dev_type, 8); + pcur += 8; + + *pcur = psta->num_of_secdev_type; + pcur++; + + memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8); + pcur += psta->num_of_secdev_type*8; + + if (psta->dev_name_len>0) + { + /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ + RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); + pcur += 2; + + /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */ + RTW_PUT_BE16(pcur, psta->dev_name_len); + pcur += 2; + + memcpy(pcur, psta->dev_name, psta->dev_name_len); + pcur += psta->dev_name_len; + } + + tmplen = (u8)(pcur-pstart); + + *pstart = (tmplen-1); + + attr_len += tmplen; + + /* pstart += tmplen; */ + pstart = pcur; + + } + + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + + if (attr_len>0) + { + len = rtw_set_p2p_attr_content23a(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); + } + + kfree(pdata_attr); + + return len; +} + +static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_DISC_REQUEST; + u8 dialogToken = 0; + + DBG_8723A("[%s]\n", __func__); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); + memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + /* Build P2P action frame header */ + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* there is no IE in this P2P action frame */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_DEVDISC_RESP; + u8 p2pie[8] = { 0x00 }; + u32 p2pielen = 0; + + DBG_8723A("[%s]\n", __func__); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); + memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + /* Build P2P public action frame header */ + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* Build P2P IE */ + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* P2P_ATTR_STATUS */ + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8* raddr, u8* frame_body, u16 config_method) +{ + struct rtw_adapter *padapter = pwdinfo->padapter; + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_RESP; + u8 wpsie[ 100 ] = { 0x00 }; + u8 wpsielen = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + wpsielen = 0; + /* WPS OUI */ + /* u32*) (wpsie) = cpu_to_be32(WPSOUI); */ + RTW_PUT_BE32(wpsie, WPSOUI); + wpsielen += 4; + + /* Config Method */ + /* Type: */ + /* u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); */ + RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + /* u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); */ + RTW_PUT_BE16(wpsie + wpsielen, 0x0002); + wpsielen += 2; + + /* Value: */ + /* u16*) (wpsie + wpsielen) = cpu_to_be16(config_method); */ + RTW_PUT_BE16(wpsie + wpsielen, config_method); + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + + return; +} + +static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PRESENCE_RESPONSE; + u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; + u8 noa_attr_content[32] = { 0x00 }; + u32 p2pielen = 0; + + DBG_8723A("[%s]\n", __func__); + + if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) + { + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *fctrl = 0; + + memcpy(pwlanhdr->addr1, da, ETH_ALEN); + memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); + memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + /* Build P2P action frame header */ + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* Add P2P IE header */ + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* Add Status attribute in P2P IE */ + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); + + /* Add NoA attribute in P2P IE */ + noa_attr_content[0] = 0x1;/* index */ + noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */ + + /* todo: Notice of Absence Descriptor(s) */ + + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, + &pattrib->pktlen); + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); +} + +u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; + u16 capability = 0; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. P2P Device ID */ + /* 3. Notice of Absence (NOA) */ + + /* P2P Capability ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + /* Be able to participate in additional P2P Groups and */ + /* support the P2P Invitation Procedure */ + /* Group Capability Bitmap, 1 byte */ + capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY; + capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) + capability |= (P2P_GRPCAP_GROUP_FORMATION<<8); + + capability = cpu_to_le16(capability); + + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8*)&capability); + + /* P2P Device ID ATTR */ + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); + + /* Notice of Absence ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + + /* go_add_noa_attr(pwdinfo); */ + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + return len; +} + +#ifdef CONFIG_8723AU_P2P +u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the beacon frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + + if (P2P_ROLE_GO == pwdinfo->role) + { + if (is_any_client_associated(pwdinfo->padapter)) + { + /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD); + } + else + { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + } + + } + else + { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + + if (1 == pwdinfo->wfd_tdls_enable) + { + /* WFD primary sink + available for WFD session + WiFi TDLS mode + WSC (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD | + WFD_DEVINFO_PC_TDLS); + } + else + { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSC (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD); + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe response frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + /* 4. WFD Session Information */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode */ + + if (true == pwdinfo->session_available) + { + if (P2P_ROLE_GO == pwdinfo->role) + { + if (is_any_client_associated(pwdinfo->padapter)) + { + if (pwdinfo->wfd_tdls_enable) + { + /* TDLS mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } + else + { + /* WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } + else + { + if (pwdinfo->wfd_tdls_enable) + { + /* available for WFD session + TDLS mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } + else + { + /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } + } + else + { + if (pwdinfo->wfd_tdls_enable) + { + /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } + else + { + + /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } + } + else + { + if (pwdinfo->wfd_tdls_enable) + { + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD |WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } + else + { + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = NULL; + struct mlme_priv *pmlmepriv = NULL; + struct wifi_display_info *pwfd_info = NULL; + + /* WFD OUI */ + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) + { + return 0; + } + + padapter = pwdinfo->padapter; + pmlmepriv = &padapter->mlmepriv; + pwfd_info = padapter->wdinfo.wfd_info; + + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + if (P2P_ROLE_GO == pwdinfo->role) + { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + if (P2P_ROLE_GO == pwdinfo->role) + { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info* pwfd_info = padapter->wdinfo.wfd_info; + + /* WFD OUI */ + wfdielen = 0; + wfdie[ wfdielen++ ] = 0x50; + wfdie[ wfdielen++ ] = 0x6F; + wfdie[ wfdielen++ ] = 0x9A; + wfdie[ wfdielen++ ] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID (Optional) */ + /* 3. Local IP Adress (Optional) */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN); + } + else + { + memset(wfdie + wfdielen, 0x00, ETH_ALEN); + } + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[ wfdielen++ ] = 0; + /* MAC Addr. */ + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + wfdie[ wfdielen++ ] = 0; + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + + return len; +} + +#endif /* CONFIG_8723AU_P2P */ + +u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20100907 */ + /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Extended Listen Timing */ + /* 3. Notice of Absence (NOA) (Only GO needs this) */ + /* 4. Device Info */ + /* 5. Group Info (Only GO need this) */ + + /* P2P Capability ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + p2pie[ p2pielen ] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) + p2pie[ p2pielen ] |= P2P_GRPCAP_GROUP_FORMATION; + + p2pielen++; + } + else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) + { + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; + } + + /* Extended Listen Timing ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ + RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ + RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + p2pielen += 2; + + /* Notice of Absence ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + /* go_add_noa_attr(pwdinfo); */ + } + + /* Device Info ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ + RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ + RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[ p2pielen++ ] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + /* Group Info ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); + } + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + return len; +} + +u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8* pssid, u8 ussidlen, u8* pdev_raddr) +{ + u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110301 */ + /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Device Info */ + /* 3. Group ID (When joining an operating P2P Group) */ + + /* P2P Capability ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT; + + /* Device Info ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ + RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) + { + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); + } + else + { + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); + } + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ + RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[ p2pielen++ ] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) + { + /* Added by Albert 2011/05/19 */ + /* In this case, the pdev_raddr is the device address of the group owner. */ + + /* P2P Group ID ATTR */ + /* Type: */ + p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID; + + /* Length: */ + /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */ + RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); + p2pielen += 2; + + /* Value: */ + memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN); + p2pielen += ETH_ALEN; + + memcpy(p2pie + p2pielen, pssid, ussidlen); + p2pielen += ussidlen; + + } + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + return len; +} + +u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) +{ + u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[ p2pielen++ ] = 0x50; + p2pie[ p2pielen++ ] = 0x6F; + p2pie[ p2pielen++ ] = 0x9A; + p2pie[ p2pielen++ ] = 0x09; /* WFA P2P v1.0 */ + + /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */ + /* 1. Status */ + /* 2. Extended Listen Timing (optional) */ + + /* Status ATTR */ + p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); + + /* Extended Listen Timing ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + + pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + return len; +} + +u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u32 len = 0; + + return len; +} + +u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *p; + u32 ret = false; + u8 *p2pie; + u32 p2pielen = 0; + int ssid_len = 0, rate_cnt = 0; + + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, + len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_); + + if (rate_cnt <= 4) + { + int i, g_rate = 0; + + for (i = 0; i < rate_cnt; i++) + { + if (((*(p + 2 + i) & 0xff) != 0x02) && + ((*(p + 2 + i) & 0xff) != 0x04) && + ((*(p + 2 + i) & 0xff) != 0x0B) && + ((*(p + 2 + i) & 0xff) != 0x16)) + { + g_rate = 1; + } + } + + if (g_rate == 0) + { + /* There is no OFDM rate included in SupportedRates IE of this probe request frame */ + /* The driver should response this probe request. */ + return ret; + } + } + else + { + /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */ + /* We should proceed the following check for this probe request. */ + } + + /* Added comments by Albert 20100906 */ + /* There are several items we should check here. */ + /* 1. This probe request frame must contain the P2P IE. (Done) */ + /* 2. This probe request frame must contain the wildcard SSID. (Done) */ + /* 3. Wildcard BSSID. (Todo) */ + /* 4. Destination Address. (Done in mgt_dispatcher23a function) */ + /* 5. Requested Device Type in WSC IE. (Todo) */ + /* 6. Device ID attribute in P2P IE. (Todo) */ + + p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, + len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_); + + ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_, NULL, &p2pielen))) + { + if ((p) && !memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid, 7)) + { + /* todo: */ + /* Check Requested Device Type attributes in WSC IE. */ + /* Check Device ID attribute in P2P IE */ + + ret = true; + } + else if ((p != NULL) && (ssid_len == 0)) + { + ret = true; + } + } + else + { + /* non -p2p device */ + } + + } + + return ret; +} + +u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) +{ + u8 status_code = P2P_STATUS_SUCCESS; + u8 *pbuf, *pattr_content = NULL; + u32 attr_contentlen = 0; + u16 cap_attr = 0; + unsigned short ie_offset; + u8 * ies; + u32 ies_len; + u8 * p2p_ie; + u32 p2p_ielen = 0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; + + if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + return P2P_STATUS_FAIL_REQUEST_UNABLE; + + if (ieee80211_is_assoc_req(hdr->frame_control)) + ie_offset = _ASOCREQ_IE_OFFSET_; + else /* WIFI_REASSOCREQ */ + ie_offset = _REASOCREQ_IE_OFFSET_; + + ies = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset; + ies_len = len - sizeof(struct ieee80211_hdr_3addr) - ie_offset; + + p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); + + if (!p2p_ie) + { + DBG_8723A("[%s] P2P IE not Found!!\n", __func__); + status_code = P2P_STATUS_FAIL_INVALID_PARAM; + } + else + { + DBG_8723A("[%s] P2P IE Found!!\n", __func__); + } + + while (p2p_ie) + { + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*) &attr_contentlen)) + { + DBG_8723A("[%s] Got P2P Capability Attr!!\n", __func__); + cap_attr = le16_to_cpu(cap_attr); + psta->dev_cap = cap_attr&0xff; + } + + /* Check Extended Listen Timing ATTR */ + + /* Check P2P Device Info ATTR */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint*)&attr_contentlen)) + { + DBG_8723A("[%s] Got P2P DEVICE INFO Attr!!\n", __func__); + pattr_content = pbuf = kzalloc(attr_contentlen, + GFP_ATOMIC); + if (pattr_content) { + u8 num_of_secdev_type; + u16 dev_name_len; + + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, pattr_content, (uint*)&attr_contentlen); + + memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */ + + pattr_content += ETH_ALEN; + + memcpy(&psta->config_methods, pattr_content, 2);/* Config Methods */ + psta->config_methods = be16_to_cpu(psta->config_methods); + + pattr_content += 2; + + memcpy(psta->primary_dev_type, pattr_content, 8); + + pattr_content += 8; + + num_of_secdev_type = *pattr_content; + pattr_content += 1; + + if (num_of_secdev_type == 0) + { + psta->num_of_secdev_type = 0; + } + else + { + u32 len; + + psta->num_of_secdev_type = num_of_secdev_type; + + len = (sizeof(psta->secdev_types_list)<(num_of_secdev_type*8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8); + + memcpy(psta->secdev_types_list, pattr_content, len); + + pattr_content += (num_of_secdev_type*8); + } + + /* dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); */ + psta->dev_name_len = 0; + if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16*)pattr_content)) + { + dev_name_len = be16_to_cpu(*(u16*)(pattr_content+2)); + + psta->dev_name_len = (sizeof(psta->dev_name)dev_name):dev_name_len; + + memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len); + } + + kfree(pbuf); + + } + + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); + + } + + return status_code; +} + +u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len) +{ + u8 *frame_body; + u8 status, dialogToken; + struct sta_info *psta = NULL; + struct rtw_adapter *padapter = pwdinfo->padapter; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *p2p_ie; + u32 p2p_ielen = 0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; + + frame_body = (unsigned char *) + (pframe + sizeof(struct ieee80211_hdr_3addr)); + + dialogToken = frame_body[7]; + status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; + + if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + len - _PUBLIC_ACTION_IE_OFFSET_, NULL, + &p2p_ielen))) { + u8 groupid[38] = { 0x00 }; + u8 dev_addr[ETH_ALEN] = { 0x00 }; + u32 attr_contentlen = 0; + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, + P2P_ATTR_GROUP_ID, groupid, + &attr_contentlen)) { + if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && + !memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN, + pwdinfo->p2p_group_ssid_len)) { + attr_contentlen = 0; + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, + P2P_ATTR_DEVICE_ID, + dev_addr, + &attr_contentlen)) { + struct list_head *phead, *plist, *ptmp; + + spin_lock_bh(&pstapriv->asoc_list_lock); + phead = &pstapriv->asoc_list; + + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) && + !memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) + { + /* spin_unlock_bh(&pstapriv->asoc_list_lock); */ + /* issue GO Discoverability Request */ + issue_group_disc_req(pwdinfo, psta->hwaddr); + /* spin_lock_bh(&pstapriv->asoc_list_lock); */ + status = P2P_STATUS_SUCCESS; + break; + } else { + status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + } + spin_unlock_bh(&pstapriv->asoc_list_lock); + } else { + status = P2P_STATUS_FAIL_INVALID_PARAM; + } + } else { + status = P2P_STATUS_FAIL_INVALID_PARAM; + } + } + } + + /* issue Device Discoverability Response */ + issue_p2p_devdisc_resp(pwdinfo, hdr->addr2, status, dialogToken); + + return (status == P2P_STATUS_SUCCESS) ? true:false; +} + +u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + return true; +} + +u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo, + u8 *pframe, uint len) +{ + u8 *frame_body; + u8 *wpsie; + u8 *ptr = NULL; + uint wps_ielen = 0, attr_contentlen = 0; + u16 uconfig_method = 0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; + + frame_body = (pframe + sizeof(struct ieee80211_hdr_3addr)); + + wpsie = rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + len - _PUBLIC_ACTION_IE_OFFSET_, NULL, + &wps_ielen); + if (!wpsie) + goto out; + + if (!rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, + (u8 *)&uconfig_method, &attr_contentlen)) + goto out; + + uconfig_method = be16_to_cpu(uconfig_method); + ptr = pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req; + + switch (uconfig_method) + { + case WPS_CM_DISPLYA: + memcpy(ptr, "dis", 3); + break; + + case WPS_CM_LABEL: + memcpy(ptr, "lab", 3); + break; + + case WPS_CM_PUSH_BUTTON: + memcpy(ptr, "pbc", 3); + break; + + case WPS_CM_KEYPAD: + memcpy(ptr, "pad", 3); + break; + } + issue_p2p_provision_resp(pwdinfo, hdr->addr2, frame_body, + uconfig_method); + +out: + DBG_8723A("[%s] config method = %s\n", __func__, ptr); + + return true; +} + +u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe) +{ + + return true; +} + +static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) +{ + u8 i = 0, j = 0; + u8 temp = 0; + u8 ch_no = 0; + ch_content += 3; + ch_cnt -= 3; + + while(ch_cnt > 0) + { + ch_content += 1; + ch_cnt -= 1; + temp = *ch_content; + for (i = 0 ; i < temp ; i++, j++) + { + peer_ch_list[j] = *(ch_content + 1 + i); + } + ch_content += (temp + 1); + ch_cnt -= (temp + 1); + ch_no += temp ; + } + + return ch_no; +} + +static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) +{ + int i = 0, j = 0, temp = 0; + u8 ch_no = 0; + + for (i = 0; i < peer_ch_num; i++) + { + for (j = temp; j < pmlmeext->max_chan_nums; j++) + { + if (*(peer_ch_list + i) == pmlmeext->channel_set[ j ].ChannelNum) + { + ch_list_inclusioned[ ch_no++ ] = *(peer_ch_list + i); + temp = j; + break; + } + } + } + + return ch_no; +} + +u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + struct rtw_adapter *padapter = pwdinfo->padapter; + u8 result = P2P_STATUS_SUCCESS; + u32 p2p_ielen = 0, wps_ielen = 0; + u8 * ies; + u32 ies_len; + u8 *p2p_ie; + u8 *wpsie; + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; +#ifdef CONFIG_8723AU_P2P + u8 wfd_ie[ 128 ] = { 0x00 }; + u32 wfd_ielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + if ((wpsie = rtw_get_wps_ie23a(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen))) + { + /* Commented by Kurt 20120113 */ + /* If some device wants to do p2p handshake without sending prov_disc_req */ + /* We have to get peer_req_cm from here. */ + if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) + { + rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len); + wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); + + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) + { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); + } + else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) + { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); + } + else + { + memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); + } + } + } + else + { + DBG_8723A("[%s] WPS IE not Found!!\n", __func__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + return result; + } + + if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) + { + result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); + return result; + } + + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); + + if (!p2p_ie) + { + DBG_8723A("[%s] P2P IE not Found!!\n", __func__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + + while (p2p_ie) + { + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + u8 ch_content[50] = { 0x00 }; + uint ch_cnt = 0; + u8 peer_ch_list[50] = { 0x00 }; + u8 peer_ch_num = 0; + u8 ch_list_inclusioned[50] = { 0x00 }; + u8 ch_num_inclusioned = 0; + u16 cap_attr; + + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); + + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen)) + cap_attr = le16_to_cpu(cap_attr); + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) + { + DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); + pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ + + if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) + { + /* Try to match the tie breaker value */ + if (pwdinfo->intent == P2P_MAX_INTENT) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; + } + else + { + if (attr_content & 0x01) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + } + } + else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + /* Store the group id information. */ + memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); + memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + } + } + + attr_contentlen = 0; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) + { + if (attr_contentlen != ETH_ALEN) + { + memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + } + } + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) + { + peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); + ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); + + if (ch_num_inclusioned == 0) + { + DBG_8723A("[%s] No common channel in channel list!\n", __func__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, + ch_list_inclusioned, ch_num_inclusioned)) + { + { + u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; + attr_contentlen = 0; + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + { + peer_operating_ch = operatingch_info[4]; + } + + if (rtw_p2p_is_channel_list_ok(peer_operating_ch, + ch_list_inclusioned, ch_num_inclusioned)) + { + /** + * Change our operating channel as peer's for compatibility. + */ + pwdinfo->operating_channel = peer_operating_ch; + DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); + } + else + { + /* Take first channel of ch_list_inclusioned as operating channel */ + pwdinfo->operating_channel = ch_list_inclusioned[0]; + DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); + } + } + + } + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); + } + +#ifdef CONFIG_8723AU_P2P + /* Added by Albert 20110823 */ + /* Try to get the TCP port information when receiving the negotiation request. */ + if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen)) + { + u8 attr_content[ 10 ] = { 0x00 }; + u32 attr_contentlen = 0; + + DBG_8723A("[%s] WFD IE Found!!\n", __func__); + rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); + if (attr_contentlen) + { + pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); + } + } +#endif /* CONFIG_8723AU_P2P */ + + return result; +} + +u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + struct rtw_adapter *padapter = pwdinfo->padapter; + u8 result = P2P_STATUS_SUCCESS; + u32 p2p_ielen, wps_ielen; + u8 * ies; + u32 ies_len; + u8 * p2p_ie; +#ifdef CONFIG_8723AU_P2P + u8 wfd_ie[ 128 ] = { 0x00 }; + u32 wfd_ielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + /* Be able to know which one is the P2P GO and which one is P2P client. */ + + if (rtw_get_wps_ie23a(ies, ies_len, NULL, &wps_ielen)) + { + + } + else + { + DBG_8723A("[%s] WPS IE not Found!!\n", __func__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + + p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); + if (!p2p_ie) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + } + else + { + + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + u8 operatingch_info[5] = { 0x00 }; + u8 groupid[ 38 ]; + u16 cap_attr; + u8 peer_ch_list[50] = { 0x00 }; + u8 peer_ch_num = 0; + u8 ch_list_inclusioned[50] = { 0x00 }; + u8 ch_num_inclusioned = 0; + + while (p2p_ie) /* Found the P2P IE. */ + { + + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen)) + cap_attr = le16_to_cpu(cap_attr); + + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + if (attr_contentlen == 1) + { + DBG_8723A("[%s] Status = %d\n", __func__, attr_content); + if (attr_content == P2P_STATUS_SUCCESS) + { + /* Do nothing. */ + } + else + { + if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) { + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); + } else { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = attr_content; + break; + } + } + + /* Try to get the peer's interface address */ + attr_contentlen = 0; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) + { + if (attr_contentlen != ETH_ALEN) + { + memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + } + } + + /* Try to get the peer's intent and tie breaker value. */ + attr_content = 0x00; + attr_contentlen = 0; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) + { + DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); + pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ + + if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) + { + /* Try to match the tie breaker value */ + if (pwdinfo->intent == P2P_MAX_INTENT) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + else + { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + if (attr_content & 0x01) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + } + } + else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) + { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + else + { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + /* Store the group id information. */ + memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); + memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + + } + } + + /* Try to get the operation channel information */ + + attr_contentlen = 0; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + { + DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); + pwdinfo->peer_operating_ch = operatingch_info[4]; + } + + /* Try to get the channel list information */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) + { + DBG_8723A("[%s] channel list attribute found, len = %d\n", __func__, pwdinfo->channel_list_attr_len); + + peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); + ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); + + if (ch_num_inclusioned == 0) + { + DBG_8723A("[%s] No common channel in channel list!\n", __func__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + { + if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, + ch_list_inclusioned, ch_num_inclusioned)) + { + { + u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; + attr_contentlen = 0; + + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + { + peer_operating_ch = operatingch_info[4]; + } + + if (rtw_p2p_is_channel_list_ok(peer_operating_ch, + ch_list_inclusioned, ch_num_inclusioned)) + { + /** + * Change our operating channel as peer's for compatibility. + */ + pwdinfo->operating_channel = peer_operating_ch; + DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); + } + else + { + /* Take first channel of ch_list_inclusioned as operating channel */ + pwdinfo->operating_channel = ch_list_inclusioned[0]; + DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); + } + } + + } + } + + } + else + { + DBG_8723A("[%s] channel list attribute not found!\n", __func__); + } + + /* Try to get the group id information if peer is GO */ + attr_contentlen = 0; + memset(groupid, 0x00, 38); + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) + { + memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); + memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); + } + + } + +#ifdef CONFIG_8723AU_P2P + /* Added by Albert 20111122 */ + /* Try to get the TCP port information when receiving the negotiation response. */ + if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen)) + { + u8 attr_content[ 10 ] = { 0x00 }; + u32 attr_contentlen = 0; + + DBG_8723A("[%s] WFD IE Found!!\n", __func__); + rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); + if (attr_contentlen) + { + pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); + } + } +#endif /* CONFIG_8723AU_P2P */ + + return result; +} + +u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 * ies; + u32 ies_len; + u8 * p2p_ie; + u32 p2p_ielen = 0; + u8 result = P2P_STATUS_SUCCESS; + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); + while (p2p_ie) /* Found the P2P IE. */ + { + u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; + u8 groupid[ 38 ] = { 0x00 }; + u32 attr_contentlen = 0; + + pwdinfo->negotiation_dialog_token = 1; + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + if (attr_contentlen == 1) + { + DBG_8723A("[%s] Status = %d\n", __func__, attr_content); + result = attr_content; + + if (attr_content == P2P_STATUS_SUCCESS) + { + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + + /* Commented by Albert 20100911 */ + /* Todo: Need to handle the case which both Intents are the same. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + else + { + /* Have to compare the Tie Breaker */ + if (pwdinfo->peer_intent & 0x01) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + } + } + else + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + } + + /* Try to get the group id information */ + attr_contentlen = 0; + memset(groupid, 0x00, 38); + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) + { + DBG_8723A("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN])); + memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); + memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); + } + + attr_contentlen = 0; + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + { + DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); + pwdinfo->peer_operating_ch = operatingch_info[4]; + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); + + } + + return result; +} + +u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *frame_body; + u8 dialogToken = 0; + u8 status = P2P_STATUS_SUCCESS; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; + + frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); + + dialogToken = frame_body[6]; + + /* todo: check NoA attribute */ + + issue_p2p_presence_resp(pwdinfo, hdr->addr2, status, dialogToken); + + return true; +} + +static void find_phase_handler(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct cfg80211_ssid ssid; + u8 _status = 0; + + + + memset((unsigned char*)&ssid, 0, sizeof(struct cfg80211_ssid)); + memcpy(ssid.ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); + ssid.ssid_len = P2P_WILDCARD_SSID_LEN; + + rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); + + spin_lock_bh(&pmlmepriv->lock); + _status = rtw_sitesurvey_cmd23a(padapter, &ssid, 1, NULL, 0); + spin_unlock_bh(&pmlmepriv->lock); + + +} + +void p2p_concurrent_handler(struct rtw_adapter* padapter); + +static void restore_p2p_state_handler(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { + /* In the P2P client mode, the driver should not switch back to its listen channel */ + /* because this P2P client should stay at the operating channel of P2P GO. */ + set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + } +} + +static void pre_tx_invitereq_handler(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + set_channel_bwmode23a(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue23a_probereq_p2p(padapter, NULL); + mod_timer(&pwdinfo->pre_tx_scan_timer, + jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); + + +} + +static void pre_tx_provdisc_handler(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + + set_channel_bwmode23a(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue23a_probereq_p2p(padapter, NULL); + mod_timer(&pwdinfo->pre_tx_scan_timer, + jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); + + +} + +static void pre_tx_negoreq_handler(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + + set_channel_bwmode23a(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue23a_probereq_p2p(padapter, NULL); + mod_timer(&pwdinfo->pre_tx_scan_timer, + jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT)); + + +} + +static void ro_ch_handler(struct rtw_adapter *padapter) +{ + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (pcfg80211_wdinfo->restore_channel != pmlmeext->cur_channel) { + if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) + pmlmeext->cur_channel = pcfg80211_wdinfo->restore_channel; + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, + HAL_PRIME_CHNL_OFFSET_DONT_CARE, + HT_CHANNEL_WIDTH_20); + } + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + + pcfg80211_wdinfo->is_ro_ch = false; + + DBG_8723A("cfg80211_remain_on_channel_expired\n"); + + rtw_cfg80211_remain_on_channel_expired(padapter, + pcfg80211_wdinfo->remain_on_ch_cookie, + &pcfg80211_wdinfo->remain_on_ch_channel, + pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL); +} + +static void ro_ch_timer_process (unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + + p2p_protocol_wk_cmd23a(adapter, P2P_RO_CH_WK); +} + +#ifdef CONFIG_8723AU_P2P +void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32* len) +{ + unsigned char *frame_body; + u8 category, action, OUI_Subtype, dialogToken = 0; + u32 wfdielen = 0; + + frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); + category = frame_body[0]; + + if (category == WLAN_CATEGORY_PUBLIC) { + action = frame_body[1]; + if (action == ACT_PUBLIC_VENDOR && + !memcmp(frame_body+2, P2P_OUI23A, 4)) { + OUI_Subtype = frame_body[6]; + dialogToken = frame_body[7]; + switch (OUI_Subtype)/* OUI Subtype */ { + case P2P_GO_NEGO_REQ: + wfdielen = build_nego_req_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_GO_NEGO_RESP: + wfdielen = build_nego_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_GO_NEGO_CONF: + wfdielen = build_nego_confirm_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_INVIT_REQ: + wfdielen = build_invitation_req_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_INVIT_RESP: + wfdielen = build_invitation_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_DEVDISC_REQ: + break; + case P2P_DEVDISC_RESP: + break; + case P2P_PROVISION_DISC_REQ: + wfdielen = build_provdisc_req_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + case P2P_PROVISION_DISC_RESP: + wfdielen = build_provdisc_resp_wfd_ie(&padapter->wdinfo, buf + (*len)); + (*len) += wfdielen; + break; + default: + break; + } + } + } else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC) { + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + } else { + DBG_8723A("%s, action frame category =%d\n", __func__, category); + } +} +#endif + +int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf, u32 len, u8 tx) +{ + int is_p2p_frame = (-1); + unsigned char *frame_body; + u8 category, action, OUI_Subtype, dialogToken = 0; + u8 *p2p_ie = NULL; + uint p2p_ielen = 0; + struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); + + frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); + category = frame_body[0]; + /* just for check */ + if (category == WLAN_CATEGORY_PUBLIC) + { + action = frame_body[1]; + if (action == ACT_PUBLIC_VENDOR && + !memcmp(frame_body+2, P2P_OUI23A, 4)) { + OUI_Subtype = frame_body[6]; + dialogToken = frame_body[7]; + is_p2p_frame = OUI_Subtype; + p2p_ie = rtw_get_p2p_ie23a( + (u8 *)buf+sizeof(struct ieee80211_hdr_3addr)+_PUBLIC_ACTION_IE_OFFSET_, + len-sizeof(struct ieee80211_hdr_3addr)-_PUBLIC_ACTION_IE_OFFSET_, + NULL, &p2p_ielen); + + switch (OUI_Subtype) {/* OUI Subtype */ + u8 *cont; + uint cont_len; + case P2P_GO_NEGO_REQ: + DBG_8723A("RTW_%s:P2P_GO_NEGO_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); + break; + case P2P_GO_NEGO_RESP: + cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + DBG_8723A("RTW_%s:P2P_GO_NEGO_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); + + if (!tx) + pwdev_priv->provdisc_req_issued = false; + break; + case P2P_GO_NEGO_CONF: + cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + DBG_8723A("RTW_%s:P2P_GO_NEGO_CONF, dialogToken =%d, status:%d\n", + (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); + break; + case P2P_INVIT_REQ: + { + struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; + int flags = -1; + int op_ch = 0; + + if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len))) + flags = *cont; + if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) + op_ch = *(cont+4); + + if (invit_info->token != dialogToken) + rtw_wdev_invit_info_init(invit_info); + + invit_info->token = dialogToken; + invit_info->flags = (flags ==-1) ? 0x0 : flags; + invit_info->req_op_ch = op_ch; + + DBG_8723A("RTW_%s:P2P_INVIT_REQ, dialogToken =%d, flags:0x%02x, op_ch:%d\n", + (tx) ? "Tx" : "Rx", dialogToken, flags, op_ch); + break; + } + case P2P_INVIT_RESP: + { + struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info; + int status = -1; + int op_ch = 0; + + if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len))) + status = *cont; + if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len))) + op_ch = *(cont+4); + + if (invit_info->token != dialogToken) { + rtw_wdev_invit_info_init(invit_info); + } else { + invit_info->token = 0; + invit_info->status = (status ==-1) ? 0xff : status; + invit_info->rsp_op_ch = op_ch; + } + + DBG_8723A("RTW_%s:P2P_INVIT_RESP, dialogToken =%d, status:%d, op_ch:%d\n", + (tx == true)?"Tx":"Rx", dialogToken, status, op_ch); + break; + } + case P2P_DEVDISC_REQ: + DBG_8723A("RTW_%s:P2P_DEVDISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); + break; + case P2P_DEVDISC_RESP: + cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + DBG_8723A("RTW_%s:P2P_DEVDISC_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1); + break; + case P2P_PROVISION_DISC_REQ: + { + size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr); + u8 *p2p_ie; + uint p2p_ielen = 0; + uint contentlen = 0; + + DBG_8723A("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); + + pwdev_priv->provdisc_req_issued = false; + + p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, + NULL, &p2p_ielen); + if (p2p_ie) { + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen)) + pwdev_priv->provdisc_req_issued = false;/* case: p2p_client join p2p GO */ + else + pwdev_priv->provdisc_req_issued = true;/* case: p2p_devices connection before Nego req. */ + } + } + break; + case P2P_PROVISION_DISC_RESP: + DBG_8723A("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken); + break; + default: + DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"Tx":"Rx", OUI_Subtype, dialogToken); + break; + } + + } + + } + else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC) + { + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + + is_p2p_frame = OUI_Subtype; + + switch (OUI_Subtype) { + case P2P_NOTICE_OF_ABSENCE: + DBG_8723A("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); + break; + case P2P_PRESENCE_REQUEST: + DBG_8723A("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); + break; + case P2P_PRESENCE_RESPONSE: + DBG_8723A("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); + break; + case P2P_GO_DISC_REQUEST: + DBG_8723A("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken); + break; + default: + DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"TX":"RX", OUI_Subtype, dialogToken); + break; + } + + } else { + DBG_8723A("RTW_%s:action frame category =%d\n", (tx == true)?"TX":"RX", category); + } + return is_p2p_frame; +} + +void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter) +{ + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; + + memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info)); + + setup_timer(&pcfg80211_wdinfo->remain_on_ch_timer, + ro_ch_timer_process, (unsigned long)padapter); +} + +void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int intCmdType) +{ + switch (intCmdType) { + case P2P_FIND_PHASE_WK: + find_phase_handler(padapter); + break; + case P2P_RESTORE_STATE_WK: + restore_p2p_state_handler(padapter); + break; + case P2P_PRE_TX_PROVDISC_PROCESS_WK: + pre_tx_provdisc_handler(padapter); + break; + case P2P_PRE_TX_INVITEREQ_PROCESS_WK: + pre_tx_invitereq_handler(padapter); + break; + case P2P_PRE_TX_NEGOREQ_PROCESS_WK: + pre_tx_negoreq_handler(padapter); + break; + case P2P_RO_CH_WK: + ro_ch_handler(padapter); + break; + } +} + +#ifdef CONFIG_8723AU_P2P +void process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength) +{ + u8 * ies; + u32 ies_len; + u8 * p2p_ie; + u32 p2p_ielen = 0; + u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ + u32 attr_contentlen = 0; + + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 find_p2p = false, find_p2p_ps = false; + u8 noa_offset, noa_num, noa_index; + + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + { + return; + } + if (IELength <= _BEACON_IE_OFFSET_) + return; + + ies = IEs + _BEACON_IE_OFFSET_; + ies_len = IELength - _BEACON_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen); + + while(p2p_ie) + { + find_p2p = true; + /* Get Notice of Absence IE. */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) + { + find_p2p_ps = true; + noa_index = noa_attr[0]; + + if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) || + (noa_index != pwdinfo->noa_index))/* if index change, driver should reconfigure related setting. */ + { + pwdinfo->noa_index = noa_index; + pwdinfo->opp_ps = noa_attr[1] >> 7; + pwdinfo->ctwindow = noa_attr[1] & 0x7F; + + noa_offset = 2; + noa_num = 0; + /* NoA length should be n*(13) + 2 */ + if (attr_contentlen > 2) + { + while(noa_offset < attr_contentlen) + { + /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */ + pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; + noa_offset += 1; + + memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + noa_num++; + } + } + pwdinfo->noa_num = noa_num; + + if (pwdinfo->opp_ps == 1) + { + pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* driver should wait LPS for entering CTWindow */ + if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true) + { + p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1); + } + } + else if (pwdinfo->noa_num > 0) + { + pwdinfo->p2p_ps_mode = P2P_PS_NOA; + p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1); + } + else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) + { + p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); + } + } + + break; /* find target, just break. */ + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen); + + } + + if (find_p2p == true) + { + if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == false)) + { + p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1); + } + } + + +} + +void p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + + + /* Pre action for p2p state */ + switch (p2p_ps_state) + { + case P2P_PS_DISABLE: + pwdinfo->p2p_ps_state = p2p_ps_state; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + + pwdinfo->noa_index = 0; + pwdinfo->ctwindow = 0; + pwdinfo->opp_ps = 0; + pwdinfo->noa_num = 0; + pwdinfo->p2p_ps_mode = P2P_PS_NONE; + if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true) + { + if (pwrpriv->smart_ps == 0) + { + pwrpriv->smart_ps = 2; + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode); + } + } + break; + case P2P_PS_ENABLE: + if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { + pwdinfo->p2p_ps_state = p2p_ps_state; + + if (pwdinfo->ctwindow > 0) + { + if (pwrpriv->smart_ps != 0) + { + pwrpriv->smart_ps = 0; + DBG_8723A("%s(): Enter CTW, change SmartPS\n", __func__); + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode); + } + } + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + } + break; + case P2P_PS_SCAN: + case P2P_PS_SCAN_DONE: + case P2P_PS_ALLSTASLEEP: + if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { + pwdinfo->p2p_ps_state = p2p_ps_state; + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + } + break; + default: + break; + } + + +} + +u8 p2p_ps_wk_cmd23a(struct rtw_adapter*padapter, u8 p2p_ps_state, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return res; + + if (enqueue) { + ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), + GFP_ATOMIC); + if (!ph2c) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *) + kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); + if (pdrvextra_cmd_parm == NULL) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; + pdrvextra_cmd_parm->type_size = p2p_ps_state; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + } + else + { + p2p_ps_wk_hdl23a(padapter, p2p_ps_state); + } + +exit: + + + + return res; +} +#endif /* CONFIG_8723AU_P2P */ + +static void reset_ch_sitesurvey_timer_process(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + DBG_8723A("[%s] In\n", __func__); + /* Reset the operation channel information */ + pwdinfo->rx_invitereq_info.operation_ch[0] = 0; + pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; +} + +static void reset_ch_sitesurvey_timer_process2(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + DBG_8723A("[%s] In\n", __func__); + /* Reset the operation channel information */ + pwdinfo->p2p_info.operation_ch[0] = 0; + pwdinfo->p2p_info.scan_op_ch_only = 0; +} + +static void restore_p2p_state_timer_process (unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + p2p_protocol_wk_cmd23a(adapter, P2P_RESTORE_STATE_WK); +} + +static void pre_tx_scan_timer_process (unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + spin_lock_bh(&pmlmepriv->lock); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) + { + if (true == pwdinfo->tx_prov_disc_info.benable) /* the provision discovery request frame is trigger to send or not */ + { + p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK); + /* issue23a_probereq_p2p(adapter, NULL); */ + /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */ + } + } + else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) + { + if (true == pwdinfo->nego_req_info.benable) + { + p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK); + } + } + else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) + { + if (true == pwdinfo->invitereq_info.benable) + { + p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK); + } + } + else + { + DBG_8723A("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo)); + } + + spin_unlock_bh(&pmlmepriv->lock); +} + +static void find_phase_timer_process (unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + adapter->wdinfo.find_phase_state_exchange_cnt++; + + p2p_protocol_wk_cmd23a(adapter, P2P_FIND_PHASE_WK); +} + +void reset_global_wifidirect_info23a(struct rtw_adapter *padapter) +{ + struct wifidirect_info *pwdinfo; + + pwdinfo = &padapter->wdinfo; + pwdinfo->persistent_supported = 0; + pwdinfo->session_available = true; + pwdinfo->wfd_tdls_enable = 0; + pwdinfo->wfd_tdls_weaksec = 0; +} + +#ifdef CONFIG_8723AU_P2P +int rtw_init_wifi_display_info(struct rtw_adapter* padapter) +{ + int res = _SUCCESS; + struct wifi_display_info *pwfd_info = &padapter->wfd_info; + + /* Used in P2P and TDLS */ + pwfd_info->rtsp_ctrlport = 554; + pwfd_info->peer_rtsp_ctrlport = 0; /* Reset to 0 */ + pwfd_info->wfd_enable = false; + pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK; + pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; + + /* Used in P2P */ + pwfd_info->peer_session_avail = true; + pwfd_info->wfd_pc = false; + + /* Used in TDLS */ + memset(pwfd_info->ip_address, 0x00, 4); + memset(pwfd_info->peer_ip_address, 0x00, 4); + return res; +} +#endif /* CONFIG_8723AU_P2P */ + +void rtw_init_wifidirect_timers23a(struct rtw_adapter* padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + setup_timer(&pwdinfo->find_phase_timer, find_phase_timer_process, + (unsigned long)padapter); + setup_timer(&pwdinfo->restore_p2p_state_timer, + restore_p2p_state_timer_process, (unsigned long)padapter); + setup_timer(&pwdinfo->pre_tx_scan_timer, pre_tx_scan_timer_process, + (unsigned long)padapter); + setup_timer(&pwdinfo->reset_ch_sitesurvey, + reset_ch_sitesurvey_timer_process, (unsigned long)padapter); + setup_timer(&pwdinfo->reset_ch_sitesurvey2, + reset_ch_sitesurvey_timer_process2, + (unsigned long)padapter); +} + +void rtw_init_wifidirect_addrs23a(struct rtw_adapter* padapter, u8 *dev_addr, u8 *iface_addr) +{ +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + /*init device&interface address */ + if (dev_addr) { + memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); + } + if (iface_addr) { + memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); + } +#endif +} + +void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role) +{ + struct wifidirect_info *pwdinfo; +#ifdef CONFIG_8723AU_P2P + struct wifi_display_info *pwfd_info = &padapter->wfd_info; +#endif + + pwdinfo = &padapter->wdinfo; + + pwdinfo->padapter = padapter; + + /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */ + pwdinfo->social_chan[0] = 1; + pwdinfo->social_chan[1] = 6; + pwdinfo->social_chan[2] = 11; + pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */ + + /* Use the channel 11 as the listen channel */ + pwdinfo->listen_channel = 11; + + if (role == P2P_ROLE_DEVICE) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); + pwdinfo->intent = 1; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); + } + else if (role == P2P_ROLE_CLIENT) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + pwdinfo->intent = 1; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + } + else if (role == P2P_ROLE_GO) + { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + pwdinfo->intent = 15; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + } + +/* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ + pwdinfo->support_rate[0] = 0x8c; /* 6(B) */ + pwdinfo->support_rate[1] = 0x92; /* 9(B) */ + pwdinfo->support_rate[2] = 0x18; /* 12 */ + pwdinfo->support_rate[3] = 0x24; /* 18 */ + pwdinfo->support_rate[4] = 0x30; /* 24 */ + pwdinfo->support_rate[5] = 0x48; /* 36 */ + pwdinfo->support_rate[6] = 0x60; /* 48 */ + pwdinfo->support_rate[7] = 0x6c; /* 54 */ + + memcpy((void*) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7); + + memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); + pwdinfo->device_name_len = 0; + + memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info)); + pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */ + + memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info)); + pwdinfo->inviteresp_info.token = 0; + + pwdinfo->profileindex = 0; + memset(&pwdinfo->profileinfo[ 0 ], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); + + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); + + pwdinfo->listen_dwell = (u8) ((rtw_get_current_time() % 3) + 1); + /* DBG_8723A("[%s] listen_dwell time is %d00ms\n", __func__, pwdinfo->listen_dwell); */ + + memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); + pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; + + memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); + + pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; + pwdinfo->negotiation_dialog_token = 1; + + memset(pwdinfo->nego_ssid, 0x00, IEEE80211_MAX_SSID_LEN); + pwdinfo->nego_ssidlen = 0; + + pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; +#ifdef CONFIG_8723AU_P2P + pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC; + pwdinfo->wfd_info = pwfd_info; +#else + pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; +#endif /* CONFIG_8723AU_P2P */ + pwdinfo->channel_list_attr_len = 0; + memset(pwdinfo->channel_list_attr, 0x00, 100); + + memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4); + memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3); + memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); + pwdinfo->wfd_tdls_enable = 0; + memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN); + + pwdinfo->rx_invitereq_info.operation_ch[0] = 0; + pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ + pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; + pwdinfo->p2p_info.operation_ch[0] = 0; + pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ + pwdinfo->p2p_info.scan_op_ch_only = 0; +} + +int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + int ret = _SUCCESS; + + if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || + role == P2P_ROLE_GO) { + /* leave IPS/Autosuspend */ + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = _FAIL; + goto exit; + } + + /* Added by Albert 2011/03/22 */ + /* In the P2P mode, the driver should not support the b mode. */ + /* So, the Tx packet shouldn't use the CCK rate */ + update_tx_basic_rate23a(padapter, WIRELESS_11AGN); + + /* Enable P2P function */ + init_wifidirect_info23a(padapter, role); + + rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, true); + #ifdef CONFIG_8723AU_P2P + rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, true); + #endif + + } + else if (role == P2P_ROLE_DISABLE) + { + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = _FAIL; + goto exit; + } + + /* Disable P2P function */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + { + del_timer_sync(&pwdinfo->find_phase_timer); + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + del_timer_sync(&pwdinfo->pre_tx_scan_timer); + del_timer_sync(&pwdinfo->reset_ch_sitesurvey); + del_timer_sync(&pwdinfo->reset_ch_sitesurvey2); + reset_ch_sitesurvey_timer_process((unsigned long)padapter); + reset_ch_sitesurvey_timer_process2((unsigned long)padapter); + rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); + memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); + } + + rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, false); + #ifdef CONFIG_8723AU_P2P + rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, false); + #endif + + /* Restore to initial setting. */ + update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode); + } + +exit: + return ret; +} + +#endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c new file mode 100644 index 000000000000..354873ca344e --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c @@ -0,0 +1,686 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_PWRCTRL_C_ + +#include +#include +#include + +#ifdef CONFIG_8723AU_BT_COEXIST +#include +#endif + +void ips_enter23a(struct rtw_adapter * padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + down(&pwrpriv->lock); + + pwrpriv->bips_processing = true; + + /* syn ips_mode with request */ + pwrpriv->ips_mode = pwrpriv->ips_mode_req; + + pwrpriv->ips_enter23a_cnts++; + DBG_8723A("==>ips_enter23a cnts:%d\n", pwrpriv->ips_enter23a_cnts); +#ifdef CONFIG_8723AU_BT_COEXIST + BTDM_TurnOffBtCoexistBeforeEnterIPS(padapter); +#endif + if (rf_off == pwrpriv->change_rfpwrstate) + { + pwrpriv->bpower_saving = true; + DBG_8723A_LEVEL(_drv_always_, "nolinked power save enter\n"); + + if (pwrpriv->ips_mode == IPS_LEVEL_2) + pwrpriv->bkeepfwalive = true; + + rtw_ips_pwr_down23a(padapter); + pwrpriv->rf_pwrstate = rf_off; + } + pwrpriv->bips_processing = false; + + up(&pwrpriv->lock); +} + +int ips_leave23a(struct rtw_adapter * padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + int result = _SUCCESS; + int keyid; + + down(&pwrpriv->lock); + + if ((pwrpriv->rf_pwrstate == rf_off) &&!pwrpriv->bips_processing) + { + pwrpriv->bips_processing = true; + pwrpriv->change_rfpwrstate = rf_on; + pwrpriv->ips_leave23a_cnts++; + DBG_8723A("==>ips_leave23a cnts:%d\n", pwrpriv->ips_leave23a_cnts); + + if ((result = rtw_ips_pwr_up23a(padapter)) == _SUCCESS) { + pwrpriv->rf_pwrstate = rf_on; + } + DBG_8723A_LEVEL(_drv_always_, "nolinked power save leave\n"); + + if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) + { + DBG_8723A("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing); + set_channel_bwmode23a(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); + for (keyid = 0;keyid<4;keyid++) { + if (pmlmepriv->key_mask & CHKBIT(keyid)) { + if (keyid == psecuritypriv->dot11PrivacyKeyIndex) + result = rtw_set_key23a(padapter, psecuritypriv, keyid, 1); + else + result = rtw_set_key23a(padapter, psecuritypriv, keyid, 0); + } + } + } + + DBG_8723A("==> ips_leave23a.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); + pwrpriv->bips_processing = false; + + pwrpriv->bkeepfwalive = false; + pwrpriv->bpower_saving = false; + } + + up(&pwrpriv->lock); + + return result; +} + + +static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter) +{ + struct rtw_adapter *buddy = adapter->pbuddy_adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct xmit_priv *pxmit_priv = &adapter->xmitpriv; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &adapter->wdinfo; +#endif + + bool ret = false; + + if (adapter->pwrctrlpriv.ips_deny_time >= rtw_get_current_time()) + goto exit; + + if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) + || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) + || check_fwstate(pmlmepriv, WIFI_AP_STATE) + || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) + || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) + ) { + goto exit; + } + + /* consider buddy, if exist */ + if (buddy) { + struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *b_pwdinfo = &buddy->wdinfo; +#endif + + if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) + || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) + || check_fwstate(b_pmlmepriv, WIFI_AP_STATE) + || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) + || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE) + ) { + goto exit; + } + } + + if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || + pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { + DBG_8723A_LEVEL(_drv_always_, "There are some pkts to transmit\n"); + DBG_8723A_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", + pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); + goto exit; + } + + ret = true; + +exit: + return ret; +} + +void rtw_ps_processor23a(struct rtw_adapter*padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + enum rt_rf_power_state rfpwrstate; + + pwrpriv->ps_processing = true; + + if (pwrpriv->bips_processing == true) + goto exit; + + if (padapter->pwrctrlpriv.bHWPwrPindetect) { + rfpwrstate = RfOnOffDetect23a(padapter); + DBG_8723A("@@@@- #2 %s ==> rfstate:%s\n", __func__, (rfpwrstate == rf_on)?"rf_on":"rf_off"); + + if (rfpwrstate!= pwrpriv->rf_pwrstate) { + if (rfpwrstate == rf_off) { + pwrpriv->change_rfpwrstate = rf_off; + pwrpriv->brfoffbyhw = true; + padapter->bCardDisableWOHSM = true; + rtw_hw_suspend23a(padapter); + } else { + pwrpriv->change_rfpwrstate = rf_on; + rtw_hw_resume23a(padapter); + } + DBG_8723A("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on"); + } + pwrpriv->pwr_state_check_cnts ++; + } + + if (pwrpriv->ips_mode_req == IPS_NONE) + goto exit; + + if (rtw_pwr_unassociated_idle(padapter) == false) + goto exit; + + if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) + { + DBG_8723A("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv)); + pwrpriv->change_rfpwrstate = rf_off; + ips_enter23a(padapter); + } +exit: + rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); + pwrpriv->ps_processing = false; + return; +} + +static void pwr_state_check_handler(unsigned long data) +{ + struct rtw_adapter *padapter = (struct rtw_adapter *)data; + rtw_ps_cmd23a(padapter); +} + +/* + * + * Parameters + * padapter + * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 + * + */ +void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv) +{ + u8 rpwm; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + + + pslv = PS_STATE(pslv); + + if (true == pwrpriv->btcoex_rfon) + { + if (pslv < PS_STATE_S4) + pslv = PS_STATE_S3; + } + + if (pwrpriv->rpwm == pslv) { + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, + ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); + return; + } + + if ((padapter->bSurpriseRemoved == true) || + (padapter->hw_init_completed == false)) { + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, + ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", + __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); + + pwrpriv->cpwm = PS_STATE_S4; + + return; + } + + if (padapter->bDriverStopped == true) { + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, + ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); + + if (pslv < PS_STATE_S2) { + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, + ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); + return; + } + } + + rpwm = pslv | pwrpriv->tog; + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, + ("rtw_set_rpwm23a: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm)); + + pwrpriv->rpwm = pslv; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); + + pwrpriv->tog += 0x80; + pwrpriv->cpwm = pslv; + + +} + +u8 PS_RDY_CHECK(struct rtw_adapter * padapter) +{ + unsigned long delta_time; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + delta_time = jiffies - pwrpriv->DelayLPSLastTimeStamp; + + if (delta_time < LPS_DELAY_TIME) + { + return false; + } + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) || + (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) || + (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) + return false; + if (true == pwrpriv->bInSuspend) + return false; + if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) + { + DBG_8723A("Group handshake still in progress !!!\n"); + return false; + } + if (!rtw_cfg80211_pwr_mgmt(padapter)) + return false; + + return true; +} + +void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + + + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, + ("%s: PowerMode =%d Smart_PS =%d\n", + __func__, ps_mode, smart_ps)); + + if (ps_mode > PM_Card_Disable) { + RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); + return; + } + + if (pwrpriv->pwr_mode == ps_mode) + { + if (PS_MODE_ACTIVE == ps_mode) return; + + if ((pwrpriv->smart_ps == smart_ps) && + (pwrpriv->bcn_ant_mode == bcn_ant_mode)) + { + return; + } + } + + if (ps_mode == PS_MODE_ACTIVE) { +#ifdef CONFIG_8723AU_P2P + if (pwdinfo->opp_ps == 0) +#endif /* CONFIG_8723AU_P2P */ + { + DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n"); + + pwrpriv->pwr_mode = ps_mode; + rtw_set_rpwm23a(padapter, PS_STATE_S4); + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); + pwrpriv->bFwCurrentInPSMode = false; + } + } + else + { + if (PS_RDY_CHECK(padapter) +#ifdef CONFIG_8723AU_BT_COEXIST + || (BT_1Ant(padapter) == true) +#endif + ) + { + DBG_8723A("%s: Enter 802.11 power save\n", __func__); + + pwrpriv->bFwCurrentInPSMode = true; + pwrpriv->pwr_mode = ps_mode; + pwrpriv->smart_ps = smart_ps; + pwrpriv->bcn_ant_mode = bcn_ant_mode; + rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); + +#ifdef CONFIG_8723AU_P2P + /* Set CTWindow after LPS */ + if (pwdinfo->opp_ps == 1) + p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 0); +#endif /* CONFIG_8723AU_P2P */ + + rtw_set_rpwm23a(padapter, PS_STATE_S2); + } + } + + +} + +/* + * Return: + * 0: Leave OK + * -1: Timeout + * -2: Other error + */ +s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms) +{ + u32 start_time; + u8 bAwake = false; + s32 err = 0; + + start_time = rtw_get_current_time(); + while (1) + { + rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); + if (true == bAwake) + break; + + if (true == padapter->bSurpriseRemoved) + { + err = -2; + DBG_8723A("%s: device surprise removed!!\n", __func__); + break; + } + + if (rtw_get_passing_time_ms23a(start_time) > delay_ms) + { + err = -1; + DBG_8723A("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); + break; + } + udelay(100); + } + + return err; +} + +/* Description: */ +/* Enter the leisure power save mode. */ +void LPS_Enter23a(struct rtw_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + if (!PS_RDY_CHECK(padapter)) + return; + + if (pwrpriv->bLeisurePs) { + /* Idle for a while if we connect to AP a while ago. */ + if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { + pwrpriv->bpower_saving = true; + DBG_8723A("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); + /* For Tenda W311R IOT issue */ + rtw_set_ps_mode23a(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0); + } + } else { + pwrpriv->LpsIdleCount++; + } + } +} + +/* Description: */ +/* Leave the leisure power save mode. */ +void LPS_Leave23a(struct rtw_adapter *padapter) +{ +#define LPS_LEAVE_TIMEOUT_MS 100 + + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + + if (pwrpriv->bLeisurePs) { + if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { + rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0); + + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + LPS_RF_ON_check23a(padapter, LPS_LEAVE_TIMEOUT_MS); + } + } + + pwrpriv->bpower_saving = false; +} + +/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ +/* Move code to function by tynli. 2010.03.26. */ +void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter) +{ + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + u8 enqueue = 0; + + + + /* DBG_8723A("%s.....\n", __func__); */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { /* connect */ +#ifdef CONFIG_8723AU_P2P + p2p_ps_wk_cmd23a(Adapter, P2P_PS_DISABLE, enqueue); +#endif /* CONFIG_8723AU_P2P */ + + rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue); + } + + +} + +void rtw_init_pwrctrl_priv23a(struct rtw_adapter *padapter) +{ + struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; + + sema_init(&pwrctrlpriv->lock, 1); + pwrctrlpriv->rf_pwrstate = rf_on; + pwrctrlpriv->ips_enter23a_cnts = 0; + pwrctrlpriv->ips_leave23a_cnts = 0; + pwrctrlpriv->bips_processing = false; + + pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; + pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; + + pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; + pwrctrlpriv->pwr_state_check_cnts = 0; + pwrctrlpriv->bInternalAutoSuspend = false; + pwrctrlpriv->bInSuspend = false; + pwrctrlpriv->bkeepfwalive = false; + + pwrctrlpriv->LpsIdleCount = 0; + pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ + pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false; + + pwrctrlpriv->bFwCurrentInPSMode = false; + + pwrctrlpriv->rpwm = 0; + pwrctrlpriv->cpwm = PS_STATE_S4; + + pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; + pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; + pwrctrlpriv->bcn_ant_mode = 0; + + pwrctrlpriv->tog = 0x80; + + pwrctrlpriv->btcoex_rfon = false; + + setup_timer(&pwrctrlpriv->pwr_state_check_timer, + pwr_state_check_handler, (unsigned long)padapter); + + +} + +void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter) +{ +} + +u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8* val) +{ + u8 bResult = true; + rtw_hal_intf_ps_func23a(padapter, efunc_id, val); + + return bResult; +} + +inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ms); +} + +/* +* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend +* @adapter: pointer to _adapter structure +* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup +* Return _SUCCESS or _FAIL +*/ + +int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + int ret = _SUCCESS; + u32 start = rtw_get_current_time(); + + if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms)) + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms); + + if (pwrpriv->ps_processing) { + DBG_8723A("%s wait ps_processing...\n", __func__); + while (pwrpriv->ps_processing && rtw_get_passing_time_ms23a(start) <= 3000) + msleep(10); + if (pwrpriv->ps_processing) + DBG_8723A("%s wait ps_processing timeout\n", __func__); + else + DBG_8723A("%s wait ps_processing done\n", __func__); + } + + if (rtw_hal_sreset_inprogress(padapter)) { + DBG_8723A("%s wait sreset_inprogress...\n", __func__); + while (rtw_hal_sreset_inprogress(padapter) && rtw_get_passing_time_ms23a(start) <= 4000) + msleep(10); + if (rtw_hal_sreset_inprogress(padapter)) + DBG_8723A("%s wait sreset_inprogress timeout\n", __func__); + else + DBG_8723A("%s wait sreset_inprogress done\n", __func__); + } + + if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) { + DBG_8723A("%s wait bInSuspend...\n", __func__); + while (pwrpriv->bInSuspend && + (rtw_get_passing_time_ms23a(start) <= 3000)) { + msleep(10); + } + if (pwrpriv->bInSuspend) + DBG_8723A("%s wait bInSuspend timeout\n", __func__); + else + DBG_8723A("%s wait bInSuspend done\n", __func__); + } + + /* System suspend is not allowed to wakeup */ + if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) { + ret = _FAIL; + goto exit; + } + + /* block??? */ + if ((pwrpriv->bInternalAutoSuspend == true) && (padapter->net_closed == true)) { + ret = _FAIL; + goto exit; + } + + /* I think this should be check in IPS, LPS, autosuspend functions... */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == true) + { + ret = _SUCCESS; + goto exit; + } + + if (rf_off == pwrpriv->rf_pwrstate) { + DBG_8723A("%s call ips_leave23a....\n", __func__); + if (_FAIL == ips_leave23a(padapter)) { + DBG_8723A("======> ips_leave23a fail.............\n"); + ret = _FAIL; + goto exit; + } + } + + /* TODO: the following checking need to be merged... */ + if (padapter->bDriverStopped || !padapter->bup || + !padapter->hw_init_completed) { + DBG_8723A("%s: bDriverStopped =%d, bup =%d, hw_init_completed " + "=%u\n", caller, padapter->bDriverStopped, + padapter->bup, padapter->hw_init_completed); + ret = false; + goto exit; + } + +exit: + if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms)) + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms); + return ret; +} + +int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode) +{ + int ret = 0; + struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; + + if (mode < PS_MODE_NUM) + { + if (pwrctrlpriv->power_mgnt != mode) + { + if (PS_MODE_ACTIVE == mode) + { + LeaveAllPowerSaveMode23a(padapter); + } + else + { + pwrctrlpriv->LpsIdleCount = 2; + } + pwrctrlpriv->power_mgnt = mode; + pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false; + } + } + else + { + ret = -EINVAL; + } + + return ret; +} + +int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode) +{ + struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; + + if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { + rtw_ips_mode_req(pwrctrlpriv, mode); + DBG_8723A("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2"); + return 0; + } + else if (mode == IPS_NONE) { + rtw_ips_mode_req(pwrctrlpriv, mode); + DBG_8723A("%s %s\n", __func__, "IPS_NONE"); + if ((padapter->bSurpriseRemoved == 0)&&_FAIL == rtw_pwr_wakeup(padapter)) + return -EFAULT; + } + else { + return -EINVAL; + } + return 0; +} diff --git a/drivers/staging/rtl8723au/core/rtw_recv.c b/drivers/staging/rtl8723au/core/rtw_recv.c new file mode 100644 index 000000000000..0b2455e4f5b6 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_recv.c @@ -0,0 +1,2471 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_RECV_C_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void rtw_signal_stat_timer_hdl23a(unsigned long data); + +void _rtw_init_sta_recv_priv23a(struct sta_recv_priv *psta_recvpriv) +{ + + + + spin_lock_init(&psta_recvpriv->lock); + + /* for (i = 0; iblk_strms[i]); */ + + _rtw_init_queue23a(&psta_recvpriv->defrag_q); + + +} + +int _rtw_init_recv_priv23a(struct recv_priv *precvpriv, + struct rtw_adapter *padapter) +{ + struct recv_frame *precvframe; + int i; + int res = _SUCCESS; + + + + /* We don't need to memset padapter->XXX to zero, because + adapter is allocated by rtw_zvmalloc(). */ + /* memset((unsigned char *)precvpriv, 0, sizeof (struct recv_priv)); */ + + spin_lock_init(&precvpriv->lock); + + _rtw_init_queue23a(&precvpriv->free_recv_queue); + _rtw_init_queue23a(&precvpriv->recv_pending_queue); + _rtw_init_queue23a(&precvpriv->uc_swdec_pending_queue); + + precvpriv->adapter = padapter; + + precvpriv->free_recvframe_cnt = NR_RECVFRAME; + + precvpriv->pallocated_frame_buf = + rtw_zvmalloc(NR_RECVFRAME * sizeof(struct recv_frame)); + + if (precvpriv->pallocated_frame_buf == NULL) { + res = _FAIL; + goto exit; + } + + precvframe = precvpriv->pallocated_frame_buf; + + for (i = 0; i < NR_RECVFRAME ; i++) { + INIT_LIST_HEAD(&precvframe->list); + + list_add_tail(&precvframe->list, + &precvpriv->free_recv_queue.queue); + + res = rtw_os_recv_resource_alloc23a(padapter, precvframe); + + precvframe->adapter = padapter; + precvframe++; + } + + precvpriv->rx_pending_cnt = 1; + + sema_init(&precvpriv->allrxreturnevt, 0); + + res = rtw_hal_init23a_recv_priv(padapter); + + setup_timer(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl23a, + (unsigned long)padapter); + + precvpriv->signal_stat_sampling_interval = 1000; /* ms */ + + rtw_set_signal_stat_timer(precvpriv); + +exit: + + + + return res; +} + +void _rtw_free_recv_priv23a (struct recv_priv *precvpriv) +{ + struct rtw_adapter *padapter = precvpriv->adapter; + + + + rtw_free_uc_swdec_pending_queue23a(padapter); + + if (precvpriv->pallocated_frame_buf) { + rtw_vmfree(precvpriv->pallocated_frame_buf, + NR_RECVFRAME * sizeof(struct recv_frame)); + } + + rtw_hal_free_recv_priv23a(padapter); + + +} + +struct recv_frame *rtw_alloc_recvframe23a(struct rtw_queue *pfree_recv_queue) +{ + struct recv_frame *pframe; + struct list_head *plist, *phead; + struct rtw_adapter *padapter; + struct recv_priv *precvpriv; + + spin_lock_bh(&pfree_recv_queue->lock); + + if (_rtw_queue_empty23a(pfree_recv_queue) == true) + pframe = NULL; + else { + phead = get_list_head(pfree_recv_queue); + + plist = phead->next; + + pframe = container_of(plist, struct recv_frame, list); + + list_del_init(&pframe->list); + padapter = pframe->adapter; + if (padapter) { + precvpriv = &padapter->recvpriv; + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt--; + } + } + + spin_unlock_bh(&pfree_recv_queue->lock); + + return pframe; +} + +int rtw_free_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *pfree_recv_queue) +{ + struct rtw_adapter *padapter = precvframe->adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + + + if (precvframe->pkt) { + dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */ + precvframe->pkt = NULL; + } + + spin_lock_bh(&pfree_recv_queue->lock); + + list_del_init(&precvframe->list); + + list_add_tail(&precvframe->list, get_list_head(pfree_recv_queue)); + + if (padapter) { + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt++; + } + + spin_unlock_bh(&pfree_recv_queue->lock); + + + + return _SUCCESS; +} + +int rtw_enqueue_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *queue) +{ + struct rtw_adapter *padapter = precvframe->adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + spin_lock_bh(&queue->lock); + + list_del_init(&precvframe->list); + + list_add_tail(&precvframe->list, get_list_head(queue)); + + if (padapter) { + if (queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt++; + } + + spin_unlock_bh(&queue->lock); + + return _SUCCESS; +} + +/* +caller : defrag ; recvframe_chk_defrag23a in recv_thread (passive) +pframequeue: defrag_queue : will be accessed in recv_thread (passive) + +using spinlock to protect + +*/ + +void rtw_free_recvframe23a_queue(struct rtw_queue *pframequeue, struct rtw_queue *pfree_recv_queue) +{ + struct recv_frame *hdr; + struct list_head *plist, *phead, *ptmp; + + + spin_lock(&pframequeue->lock); + + phead = get_list_head(pframequeue); + plist = phead->next; + + list_for_each_safe(plist, ptmp, phead) { + hdr = container_of(plist, struct recv_frame, list); + rtw_free_recvframe23a(hdr, pfree_recv_queue); + } + + spin_unlock(&pframequeue->lock); + + +} + +u32 rtw_free_uc_swdec_pending_queue23a(struct rtw_adapter *adapter) +{ + u32 cnt = 0; + struct recv_frame *pending_frame; + while ((pending_frame = rtw_alloc_recvframe23a(&adapter->recvpriv.uc_swdec_pending_queue))) { + rtw_free_recvframe23a(pending_frame, + &adapter->recvpriv.free_recv_queue); + DBG_8723A("%s: dequeue uc_swdec_pending_queue\n", __func__); + cnt++; + } + + return cnt; +} + +int rtw_enqueue_recvbuf23a_to_head(struct recv_buf *precvbuf, struct rtw_queue *queue) +{ + spin_lock_bh(&queue->lock); + + list_del_init(&precvbuf->list); + list_add(&precvbuf->list, get_list_head(queue)); + + spin_unlock_bh(&queue->lock); + + return _SUCCESS; +} + +int rtw_enqueue_recvbuf23a(struct recv_buf *precvbuf, struct rtw_queue *queue) +{ + unsigned long irqL; + spin_lock_irqsave(&queue->lock, irqL); + + list_del_init(&precvbuf->list); + + list_add_tail(&precvbuf->list, get_list_head(queue)); + spin_unlock_irqrestore(&queue->lock, irqL); + return _SUCCESS; +} + +struct recv_buf *rtw_dequeue_recvbuf23a (struct rtw_queue *queue) +{ + unsigned long irqL; + struct recv_buf *precvbuf; + struct list_head *plist, *phead; + + spin_lock_irqsave(&queue->lock, irqL); + + if (_rtw_queue_empty23a(queue) == true) { + precvbuf = NULL; + } else { + phead = get_list_head(queue); + + plist = phead->next; + + precvbuf = container_of(plist, struct recv_buf, list); + + list_del_init(&precvbuf->list); + } + + spin_unlock_irqrestore(&queue->lock, irqL); + + return precvbuf; +} + +int recvframe_chkmic(struct rtw_adapter *adapter, + struct recv_frame *precvframe); +int recvframe_chkmic(struct rtw_adapter *adapter, + struct recv_frame *precvframe) { + + int i, res = _SUCCESS; + u32 datalen; + u8 miccode[8]; + u8 bmic_err = false, brpt_micerror = true; + u8 *pframe, *payload,*pframemic; + u8 *mickey; + /* u8 *iv, rxdata_key_idx = 0; */ + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + + stainfo = rtw_get_stainfo23a(&adapter->stapriv, &prxattrib->ta[0]); + + if (prxattrib->encrypt == _TKIP_) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n recvframe_chkmic:prxattrib->encrypt == _TKIP_\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n recvframe_chkmic:da = 0x%02x:0x%02x:0x%02x:0x%02x:" + "0x%02x:0x%02x\n", prxattrib->ra[0], + prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], + prxattrib->ra[4], prxattrib->ra[5])); + + /* calculate mic code */ + if (stainfo != NULL) { + if (is_multicast_ether_addr(prxattrib->ra)) { + mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n recvframe_chkmic: bcmc key\n")); + + if (psecuritypriv->binstallGrpkey == false) { + res = _FAIL; + RT_TRACE(_module_rtl871x_recv_c_, + _drv_err_, + ("\n recvframe_chkmic:didn't " + "install group key!!!!!!\n")); + DBG_8723A("\n recvframe_chkmic:didn't " + "install group key!!!!!!\n"); + goto exit; + } + } else { + mickey = &stainfo->dot11tkiprxmickey.skey[0]; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n recvframe_chkmic: unicast " + "key\n")); + } + + /* icv_len included the mic code */ + datalen = precvframe->pkt->len-prxattrib-> + hdrlen-prxattrib->iv_len-prxattrib->icv_len - 8; + pframe = precvframe->pkt->data; + payload = pframe + prxattrib->hdrlen + + prxattrib->iv_len; + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n prxattrib->iv_len =%d prxattrib->icv_len =" + "%d\n", prxattrib->iv_len, + prxattrib->icv_len)); + + /* care the length of the data */ + rtw_seccalctkipmic23a(mickey, pframe, payload, + datalen, &miccode[0], + (unsigned char)prxattrib->priority); + + pframemic = payload + datalen; + + bmic_err = false; + + for (i = 0; i < 8; i++) { + if (miccode[i] != *(pframemic + i)) { + RT_TRACE(_module_rtl871x_recv_c_, + _drv_err_, + ("recvframe_chkmic:miccode" + "[%d](%02x) != *(pframemic+" + "%d)(%02x) ", i, miccode[i], + i, *(pframemic + i))); + bmic_err = true; + } + } + + if (bmic_err == true) { + int i; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n *(pframemic-8)-*(pframemic-1) =" + "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:" + "0x%02x:0x%02x:0x%02x\n", + *(pframemic - 8), *(pframemic - 7), + *(pframemic - 6), *(pframemic - 5), + *(pframemic - 4), *(pframemic - 3), + *(pframemic - 2), *(pframemic - 1))); + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n *(pframemic-16)-*(pframemic-9) =" + "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:" + "0x%02x:0x%02x:0x%02x\n", + *(pframemic - 16), *(pframemic - 15), + *(pframemic - 14), *(pframemic - 13), + *(pframemic - 12), *(pframemic - 11), + *(pframemic - 10), *(pframemic - 9))); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n ====== demp packet (len =%d) ======" + "\n", precvframe->pkt->len)); + for (i = 0; i < precvframe->pkt->len; i = i + 8) { + RT_TRACE(_module_rtl871x_recv_c_, + _drv_err_, ("0x%02x:0x%02x:0x" + "%02x:0x%02x:0x%0" + "2x:0x%02x:0x%02x" + ":0x%02x", + *(precvframe->pkt->data+i),*(precvframe->pkt->data+i+1), + *(precvframe->pkt->data+i+2),*(precvframe->pkt->data+i+3), + *(precvframe->pkt->data+i+4),*(precvframe->pkt->data+i+5), + *(precvframe->pkt->data+i+6),*(precvframe->pkt->data+i+7))); + } + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n ====== demp packet end [len =%d]" + "======\n", precvframe->pkt->len)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("\n hrdlen =%d,\n", + prxattrib->hdrlen)); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("ra = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%." + "2x 0x%.2x psecuritypriv->" + "binstallGrpkey =%d ", + prxattrib->ra[0], prxattrib->ra[1], + prxattrib->ra[2], prxattrib->ra[3], + prxattrib->ra[4], prxattrib->ra[5], + psecuritypriv->binstallGrpkey)); + + /* double check key_index for some timing + issue, cannot compare with + psecuritypriv->dot118021XGrpKeyid also + cause timing issue */ + if ((is_multicast_ether_addr(prxattrib->ra)) && + (prxattrib->key_index != + pmlmeinfo->key_index)) + brpt_micerror = false; + + if ((prxattrib->bdecrypted == true) && + (brpt_micerror == true)) { + rtw_handle_tkip_mic_err23a(adapter, (u8)is_multicast_ether_addr(prxattrib->ra)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted)); + DBG_8723A(" mic error :prxattrib->" + "bdecrypted =%d\n", + prxattrib->bdecrypted); + } else { + RT_TRACE(_module_rtl871x_recv_c_, + _drv_err_, + (" mic error :prxattrib->" + "bdecrypted =%d ", + prxattrib->bdecrypted)); + DBG_8723A(" mic error :prxattrib->" + "bdecrypted =%d\n", + prxattrib->bdecrypted); + } + + res = _FAIL; + } else { + /* mic checked ok */ + if ((psecuritypriv->bcheck_grpkey == false) && + (is_multicast_ether_addr(prxattrib->ra))) { + psecuritypriv->bcheck_grpkey = true; + RT_TRACE(_module_rtl871x_recv_c_, + _drv_err_, + ("psecuritypriv->bcheck_grp" + "key = true")); + } + } + } else { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recvframe_chkmic: rtw_get_stainfo23a ==" + "NULL!!!\n")); + } + + skb_trim(precvframe->pkt, precvframe->pkt->len - 8); + } + +exit: + + + + return res; +} + +/* decrypt and set the ivlen, icvlen of the recv_frame */ +struct recv_frame *decryptor(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +struct recv_frame *decryptor(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + struct rx_pkt_attrib *prxattrib = &precv_frame->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct recv_frame *return_packet = precv_frame; + u32 res = _SUCCESS; + + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("prxstat->decrypted =%x prxattrib->encrypt = 0x%03x\n", + prxattrib->bdecrypted, prxattrib->encrypt)); + + if (prxattrib->encrypt > 0) { + u8 *iv = precv_frame->pkt->data + prxattrib->hdrlen; + prxattrib->key_index = (((iv[3]) >> 6) & 0x3); + + if (prxattrib->key_index > WEP_KEYS) { + DBG_8723A("prxattrib->key_index(%d) > WEP_KEYS\n", + prxattrib->key_index); + + switch (prxattrib->encrypt) { + case _WEP40_: + case _WEP104_: + prxattrib->key_index = + psecuritypriv->dot11PrivacyKeyIndex; + break; + case _TKIP_: + case _AES_: + default: + prxattrib->key_index = + psecuritypriv->dot118021XGrpKeyid; + break; + } + } + } + + if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0))) { + psecuritypriv->hw_decrypted = false; + switch (prxattrib->encrypt) { + case _WEP40_: + case _WEP104_: + rtw_wep_decrypt23a(padapter, precv_frame); + break; + case _TKIP_: + res = rtw_tkip_decrypt23a(padapter, precv_frame); + break; + case _AES_: + res = rtw_aes_decrypt23a(padapter, precv_frame); + break; + default: + break; + } + } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && + (psecuritypriv->busetkipkey == 1 || + prxattrib->encrypt != _TKIP_)) { + psecuritypriv->hw_decrypted = true; + } + + if (res == _FAIL) { + rtw_free_recvframe23a(return_packet, + &padapter->recvpriv.free_recv_queue); + return_packet = NULL; + } + + + + return return_packet; +} + +/* set the security information in the recv_frame */ +static struct recv_frame *portctrl(struct rtw_adapter *adapter, + struct recv_frame *precv_frame) +{ + u8 *psta_addr = NULL, *ptr; + uint auth_alg; + struct recv_frame *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv ; + struct recv_frame *prtnframe; + u16 ether_type = 0; + u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ + struct rx_pkt_attrib *pattrib; + + pstapriv = &adapter->stapriv; + psta = rtw_get_stainfo23a(pstapriv, psta_addr); + + auth_alg = adapter->securitypriv.dot11AuthAlgrthm; + + ptr = precv_frame->pkt->data; + pfhdr = precv_frame; + pattrib = &pfhdr->attrib; + psta_addr = pattrib->ta; + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm =" + "%d\n", adapter->securitypriv.dot11AuthAlgrthm)); + + if (auth_alg == 2) { + if ((psta != NULL) && (psta->ieee8021x_blocked)) { + /* blocked */ + /* only accept EAPOL frame */ + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("########portctrl:psta->ieee8021x_blocked ==" + "1\n")); + + prtnframe = precv_frame; + + /* get ether_type */ + ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; + memcpy(ðer_type, ptr, 2); + ether_type = ntohs((unsigned short)ether_type); + + if (ether_type == eapol_type) { + prtnframe = precv_frame; + } else { + /* free this frame */ + rtw_free_recvframe23a(precv_frame, + &adapter->recvpriv.free_recv_queue); + prtnframe = NULL; + } + } else { + /* allowed */ + /* check decryption status, and decrypt the frame if needed */ + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("########portctrl:psta->ieee8021x_blocked ==" + "0\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("portctrl:precv_frame->hdr.attrib.privacy =" + "%x\n", precv_frame->attrib.privacy)); + + if (pattrib->bdecrypted == 0) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("portctrl:prxstat->decrypted =%x\n", + pattrib->bdecrypted)); + } + + prtnframe = precv_frame; + /* check is the EAPOL frame or not (Rekey) */ + if (ether_type == eapol_type) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("########portctrl:ether_type == " + "0x888e\n")); + /* check Rekey */ + + prtnframe = precv_frame; + } else { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("########portctrl:ether_type = 0x%04x" + "\n", ether_type)); + } + } + } else { + prtnframe = precv_frame; + } + + + + return prtnframe; +} + +int recv_decache(struct recv_frame *precv_frame, u8 bretry, + struct stainfo_rxcache *prxcache); +int recv_decache(struct recv_frame *precv_frame, u8 bretry, + struct stainfo_rxcache *prxcache) +{ + int tid = precv_frame->attrib.priority; + + u16 seq_ctrl = ((precv_frame->attrib.seq_num & 0xffff) << 4) | + (precv_frame->attrib.frag_num & 0xf); + + + + if (tid > 15) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("recv_decache, (tid>15)! seq_ctrl = 0x%x, tid = 0x%x\n", + seq_ctrl, tid)); + + return _FAIL; + } + + if (1) { /* if (bretry) */ + if (seq_ctrl == prxcache->tid_rxseq[tid]) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("recv_decache, seq_ctrl = 0x%x, tid = 0x%x, " + "tid_rxseq = 0x%x\n", + seq_ctrl, tid, prxcache->tid_rxseq[tid])); + + return _FAIL; + } + } + + prxcache->tid_rxseq[tid] = seq_ctrl; + + + + return _SUCCESS; +} + +void process23a_pwrbit_data(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +void process23a_pwrbit_data(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_AP_MODE + unsigned char pwrbit; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct rx_pkt_attrib *pattrib = &precv_frame->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + + psta = rtw_get_stainfo23a(pstapriv, pattrib->src); + + if (psta) { + pwrbit = ieee80211_has_pm(hdr->frame_control); + + if (pwrbit) { + if (!(psta->state & WIFI_SLEEP_STATE)) + stop_sta_xmit23a(padapter, psta); + } else { + if (psta->state & WIFI_SLEEP_STATE) + wakeup_sta_to_xmit23a(padapter, psta); + } + } + +#endif +} + +void process_wmmps_data(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +void process_wmmps_data(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_AP_MODE + struct rx_pkt_attrib *pattrib = &precv_frame->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + + psta = rtw_get_stainfo23a(pstapriv, pattrib->src); + + if (!psta) + return; + + + if (!psta->qos_option) + return; + + if (!(psta->qos_info & 0xf)) + return; + + if (psta->state & WIFI_SLEEP_STATE) { + u8 wmmps_ac = 0; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + if (wmmps_ac) { + if (psta->sleepq_ac_len > 0) { + /* process received triggered frame */ + xmit_delivery_enabled_frames23a(padapter, psta); + } else { + /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */ + issue_qos_nulldata23a(padapter, psta->hwaddr, + (u16)pattrib->priority, + 0, 0); + } + } + } + +#endif +} + +static void count_rx_stats(struct rtw_adapter *padapter, + struct recv_frame *prframe, struct sta_info *sta) +{ + int sz; + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct rx_pkt_attrib *pattrib = & prframe->attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + + sz = prframe->pkt->len; + precvpriv->rx_bytes += sz; + + padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; + + if ((!is_broadcast_ether_addr(pattrib->dst)) && + (!is_multicast_ether_addr(pattrib->dst))) + padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; + + if (sta) + psta = sta; + else + psta = prframe->psta; + + if (psta) { + pstats = &psta->sta_stats; + + pstats->rx_data_pkts++; + pstats->rx_bytes += sz; + } +} + +static int sta2sta_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame, + struct sta_info**psta) +{ + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = & precv_frame->attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = myid(&adapter->eeprompriv); + u8 *sta_addr = NULL; + int bmcast = is_multicast_ether_addr(pattrib->dst); + + + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { + + /* filter packets that SA is myself or multicast or broadcast */ + if (ether_addr_equal(myhwaddr, pattrib->src)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + (" SA == myself\n")); + ret = _FAIL; + goto exit; + } + + if (!ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) { + ret = _FAIL; + goto exit; + } + + if (ether_addr_equal(pattrib->bssid, "\x0\x0\x0\x0\x0\x0") || + ether_addr_equal(mybssid, "\x0\x0\x0\x0\x0\x0") || + !ether_addr_equal(pattrib->bssid, mybssid)) { + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->src; + } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { + /* For Station mode, sa and bssid should always be BSSID, + and DA is my mac-address */ + if (!ether_addr_equal(pattrib->bssid, pattrib->src)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("bssid != TA under STATION_MODE; drop " + "pkt\n")); + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->bssid; + + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + if (bmcast) { + /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ + if (!is_multicast_ether_addr(pattrib->bssid)) { + ret = _FAIL; + goto exit; + } + } else { /* not mc-frame */ + /* For AP mode, if DA is non-MCAST, then it must + be BSSID, and bssid == BSSID */ + if (!ether_addr_equal(pattrib->bssid, pattrib->dst)) { + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->src; + } + } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) { + ether_addr_copy(pattrib->dst, hdr->addr1); + ether_addr_copy(pattrib->src, hdr->addr2); + ether_addr_copy(pattrib->bssid, hdr->addr3); + ether_addr_copy(pattrib->ra, pattrib->dst); + ether_addr_copy(pattrib->ta, pattrib->src); + + sta_addr = mybssid; + } else { + ret = _FAIL; + } + + if (bmcast) + *psta = rtw_get_bcmc_stainfo23a(adapter); + else + *psta = rtw_get_stainfo23a(pstapriv, sta_addr); /* get ap_info */ + + if (*psta == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); + ret = _FAIL; + goto exit; + } + +exit: + + return ret; +} + +int ap2sta_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame, + struct sta_info **psta); +int ap2sta_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame, + struct sta_info **psta) +{ + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct rx_pkt_attrib *pattrib = & precv_frame->attrib; + int ret = _SUCCESS; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = myid(&adapter->eeprompriv); + int bmcast = is_multicast_ether_addr(pattrib->dst); + + + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true || + check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) { + + /* filter packets that SA is myself or multicast or broadcast */ + if (ether_addr_equal(myhwaddr, pattrib->src)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + (" SA == myself\n")); + ret = _FAIL; + goto exit; + } + + /* da should be for me */ + if (!ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + (" ap2sta_data_frame: compare DA fail; DA =" + MAC_FMT"\n", MAC_ARG(pattrib->dst))); + ret = _FAIL; + goto exit; + } + + /* check BSSID */ + if (ether_addr_equal(pattrib->bssid, "\x0\x0\x0\x0\x0\x0") || + ether_addr_equal(mybssid, "\x0\x0\x0\x0\x0\x0") || + !ether_addr_equal(pattrib->bssid, mybssid)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + (" ap2sta_data_frame: compare BSSID fail ; " + "BSSID ="MAC_FMT"\n", MAC_ARG(pattrib->bssid))); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("mybssid ="MAC_FMT"\n", MAC_ARG(mybssid))); + + if (!bmcast) { + DBG_8723A("issue_deauth23a to the nonassociated " + "ap =" MAC_FMT " for the reason(7)\n", + MAC_ARG(pattrib->bssid)); + issue_deauth23a(adapter, pattrib->bssid, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + } + + ret = _FAIL; + goto exit; + } + + if (bmcast) + *psta = rtw_get_bcmc_stainfo23a(adapter); + else + /* get ap_info */ + *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid); + + if (*psta == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("ap2sta: can't get psta under STATION_MODE ;" + " drop pkt\n")); + ret = _FAIL; + goto exit; + } + + if (ieee80211_is_nullfunc(hdr->frame_control)) { + /* No data, will not indicate to upper layer, + temporily count it here */ + count_rx_stats(adapter, precv_frame, *psta); + ret = RTW_RX_HANDLED; + goto exit; + } + + } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { + ether_addr_copy(pattrib->dst, hdr->addr1); + ether_addr_copy(pattrib->src, hdr->addr2); + ether_addr_copy(pattrib->bssid, hdr->addr3); + ether_addr_copy(pattrib->ra, pattrib->dst); + ether_addr_copy(pattrib->ta, pattrib->src); + + /* */ + ether_addr_copy(pattrib->bssid, mybssid); + + /* get sta_info */ + *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid); + if (*psta == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("can't get psta under MP_MODE ; drop pkt\n")); + ret = _FAIL; + goto exit; + } + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + /* Special case */ + ret = RTW_RX_HANDLED; + goto exit; + } else { + if (ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) { + *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid); + if (*psta == NULL) { + DBG_8723A("issue_deauth23a to the ap =" MAC_FMT + " for the reason(7)\n", + MAC_ARG(pattrib->bssid)); + + issue_deauth23a(adapter, pattrib->bssid, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + } + } + + ret = _FAIL; + } + +exit: + + + + return ret; +} + +int sta2ap_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame, + struct sta_info **psta); +int sta2ap_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame, + struct sta_info **psta) +{ + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct rx_pkt_attrib *pattrib = & precv_frame->attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + unsigned char *mybssid = get_bssid(pmlmepriv); + int ret = _SUCCESS; + + + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */ + if (!ether_addr_equal(pattrib->bssid, mybssid)) { + ret = _FAIL; + goto exit; + } + + *psta = rtw_get_stainfo23a(pstapriv, pattrib->src); + if (*psta == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("can't get psta under AP_MODE; drop pkt\n")); + DBG_8723A("issue_deauth23a to sta =" MAC_FMT + " for the reason(7)\n", + MAC_ARG(pattrib->src)); + + issue_deauth23a(adapter, pattrib->src, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + + ret = RTW_RX_HANDLED; + goto exit; + } + + process23a_pwrbit_data(adapter, precv_frame); + + /* We only get here if it's a data frame, so no need to + * confirm data frame type first */ + if (ieee80211_is_data_qos(hdr->frame_control)) + process_wmmps_data(adapter, precv_frame); + + if (ieee80211_is_nullfunc(hdr->frame_control)) { + /* No data, will not indicate to upper layer, + temporily count it here */ + count_rx_stats(adapter, precv_frame, *psta); + ret = RTW_RX_HANDLED; + goto exit; + } + } else { + u8 *myhwaddr = myid(&adapter->eeprompriv); + if (!ether_addr_equal(pattrib->ra, myhwaddr)) { + ret = RTW_RX_HANDLED; + goto exit; + } + DBG_8723A("issue_deauth23a to sta =" MAC_FMT " for the reason(7)\n", + MAC_ARG(pattrib->src)); + issue_deauth23a(adapter, pattrib->src, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + ret = RTW_RX_HANDLED; + goto exit; + } + +exit: + + + + return ret; +} + +int validate_recv_ctrl_frame(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +int validate_recv_ctrl_frame(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +#ifdef CONFIG_8723AU_AP_MODE + struct rx_pkt_attrib *pattrib = &precv_frame->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *pframe = skb->data; + + if (!ieee80211_is_ctl(hdr->frame_control)) + return _FAIL; + + /* receive the frames that ra(a1) is my address */ + if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv))) + return _FAIL; + + /* only handle ps-poll */ + if (ieee80211_is_pspoll(hdr->frame_control)) { + u16 aid; + u8 wmmps_ac = 0; + struct sta_info *psta = NULL; + + aid = GetAid(pframe); + psta = rtw_get_stainfo23a(pstapriv, hdr->addr2); + + if ((!psta) || (psta->aid != aid)) + return _FAIL; + + /* for rx pkt statistics */ + psta->sta_stats.rx_ctrl_pkts++; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(0); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(0); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(0); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(0); + break; + } + + if (wmmps_ac) + return _FAIL; + + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { + DBG_8723A("%s alive check-rx ps-poll\n", __func__); + psta->expire_to = pstapriv->expire_to; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + } + + if ((psta->state & WIFI_SLEEP_STATE) && + (pstapriv->sta_dz_bitmap & CHKBIT(psta->aid))) { + struct list_head *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + spin_lock_bh(&pxmitpriv->lock); + + xmitframe_phead = get_list_head(&psta->sleep_q); + xmitframe_plist = xmitframe_phead->next; + + if (!list_empty(xmitframe_phead)) { + pxmitframe = container_of(xmitframe_plist, + struct xmit_frame, + list); + + xmitframe_plist = xmitframe_plist->next; + + list_del_init(&pxmitframe->list); + + psta->sleepq_len--; + + if (psta->sleepq_len>0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + + /* DBG_8723A("handling ps-poll, q_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ + + rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe); + + if (psta->sleepq_len == 0) { + pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); + + /* DBG_8723A("after handling ps-poll, tim =%x\n", pstapriv->tim_bitmap); */ + + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_beacon23a(padapter, _TIM_IE_, + NULL, false); + } + + /* spin_unlock_bh(&psta->sleep_q.lock); */ + spin_unlock_bh(&pxmitpriv->lock); + + } else { + /* spin_unlock_bh(&psta->sleep_q.lock); */ + spin_unlock_bh(&pxmitpriv->lock); + + /* DBG_8723A("no buffered packets to xmit\n"); */ + if (pstapriv->tim_bitmap & CHKBIT(psta->aid)) { + if (psta->sleepq_len == 0) { + DBG_8723A("no buffered packets " + "to xmit\n"); + + /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ + issue_nulldata23a(padapter, + psta->hwaddr, + 0, 0, 0); + } else { + DBG_8723A("error!psta->sleepq" + "_len =%d\n", + psta->sleepq_len); + psta->sleepq_len = 0; + } + + pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); + + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_beacon23a(padapter, _TIM_IE_, + NULL, false); + } + } + } + } + +#endif + return _FAIL; +} + +struct recv_frame* recvframe_chk_defrag23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +int validate_recv_mgnt_frame(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); +int validate_recv_mgnt_frame(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + struct sta_info *psta; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */ + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("+validate_recv_mgnt_frame\n")); + + precv_frame = recvframe_chk_defrag23a(padapter, precv_frame); + if (precv_frame == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("%s: fragment packet\n", __func__)); + return _SUCCESS; + } + + skb = precv_frame->pkt; + hdr = (struct ieee80211_hdr *) skb->data; + + /* for rx pkt statistics */ + psta = rtw_get_stainfo23a(&padapter->stapriv, hdr->addr2); + if (psta) { + psta->sta_stats.rx_mgnt_pkts++; + + if (ieee80211_is_beacon(hdr->frame_control)) + psta->sta_stats.rx_beacon_pkts++; + else if (ieee80211_is_probe_req(hdr->frame_control)) + psta->sta_stats.rx_probereq_pkts++; + else if (ieee80211_is_probe_resp(hdr->frame_control)) { + if (ether_addr_equal(padapter->eeprompriv.mac_addr, + hdr->addr1)) + psta->sta_stats.rx_probersp_pkts++; + else if (is_broadcast_ether_addr(hdr->addr1) || + is_multicast_ether_addr(hdr->addr1)) + psta->sta_stats.rx_probersp_bm_pkts++; + else + psta->sta_stats.rx_probersp_uo_pkts++; + } + } + + mgt_dispatcher23a(padapter, precv_frame); + + return _SUCCESS; +} + +int validate_recv_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame); +int validate_recv_data_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame) +{ + u8 bretry; + u8 *psa, *pda, *pbssid; + struct sta_info *psta = NULL; + u8 *ptr = precv_frame->pkt->data; + struct rx_pkt_attrib *pattrib = & precv_frame->attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; + int ret = _SUCCESS; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + + + bretry = ieee80211_has_retry(hdr->frame_control); + pda = ieee80211_get_DA(hdr); + psa = ieee80211_get_SA(hdr); + pbssid = get_hdr_bssid(ptr); + + if (pbssid == NULL) { + ret = _FAIL; + goto exit; + } + + ether_addr_copy(pattrib->dst, pda); + ether_addr_copy(pattrib->src, psa); + + ether_addr_copy(pattrib->bssid, pbssid); + + switch (pattrib->to_fr_ds) + { + case 0: + ether_addr_copy(pattrib->ra, pda); + ether_addr_copy(pattrib->ta, psa); + ret = sta2sta_data_frame(adapter, precv_frame, &psta); + break; + + case 1: + ether_addr_copy(pattrib->ra, pda); + ether_addr_copy(pattrib->ta, pbssid); + ret = ap2sta_data_frame(adapter, precv_frame, &psta); + break; + + case 2: + ether_addr_copy(pattrib->ra, pbssid); + ether_addr_copy(pattrib->ta, psa); + ret = sta2ap_data_frame(adapter, precv_frame, &psta); + break; + + case 3: + ether_addr_copy(pattrib->ra, hdr->addr1); + ether_addr_copy(pattrib->ta, hdr->addr2); + ret = _FAIL; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n")); + break; + + default: + ret = _FAIL; + break; + } + + if ((ret == _FAIL) || (ret == RTW_RX_HANDLED)) + goto exit; + + if (!psta) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + (" after to_fr_ds_chk; psta == NULL\n")); + ret = _FAIL; + goto exit; + } + + /* psta->rssi = prxcmd->rssi; */ + /* psta->signal_quality = prxcmd->sq; */ + precv_frame->psta = psta; + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + if (ieee80211_has_a4(hdr->frame_control)) + pattrib->hdrlen += ETH_ALEN; + + /* parsing QC field */ + if (pattrib->qos == 1) { + __le16 *qptr = (__le16 *)ieee80211_get_qos_ctl(hdr); + u16 qos_ctrl = le16_to_cpu(*qptr); + + pattrib->priority = qos_ctrl & IEEE80211_QOS_CTL_TID_MASK; + pattrib->ack_policy = (qos_ctrl >> 5) & 3; + pattrib->amsdu = + (qos_ctrl & IEEE80211_QOS_CTL_A_MSDU_PRESENT) >> 7; + pattrib->hdrlen += IEEE80211_QOS_CTL_LEN; + + if (pattrib->priority != 0 && pattrib->priority != 3) { + adapter->recvpriv.bIsAnyNonBEPkts = true; + } + } else { + pattrib->priority = 0; + pattrib->ack_policy = 0; + pattrib->amsdu = 0; + } + + if (pattrib->order) { /* HT-CTRL 11n */ + pattrib->hdrlen += 4; + } + + precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; + + /* decache, drop duplicate recv packets */ + if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == + _FAIL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("decache : drop pkt\n")); + ret = _FAIL; + goto exit; + } + + if (pattrib->privacy) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("validate_recv_data_frame:pattrib->privacy =%x\n", + pattrib->privacy)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n ^^^^^^^^^^^is_multicast_ether_addr" + "(pattrib->ra(0x%02x)) =%d^^^^^^^^^^^^^^^6\n", + pattrib->ra[0], + is_multicast_ether_addr(pattrib->ra))); + + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, + is_multicast_ether_addr(pattrib->ra)); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n pattrib->encrypt =%d\n", pattrib->encrypt)); + + switch (pattrib->encrypt) + { + case _WEP40_: + case _WEP104_: + pattrib->iv_len = 4; + pattrib->icv_len = 4; + break; + case _TKIP_: + pattrib->iv_len = 8; + pattrib->icv_len = 4; + break; + case _AES_: + pattrib->iv_len = 8; + pattrib->icv_len = 8; + break; + case _SMS4_: + pattrib->iv_len = 18; + pattrib->icv_len = 16; + break; + default: + pattrib->iv_len = 0; + pattrib->icv_len = 0; + break; + } + } else { + pattrib->encrypt = 0; + pattrib->iv_len = 0; + pattrib->icv_len = 0; + } + +exit: + + + + return ret; +} + +static void dump_rx_pkt(struct sk_buff *skb, u16 type, int level) +{ + int i; + u8 *ptr; + + if ((level == 1) || + ((level == 2) && (type == IEEE80211_FTYPE_MGMT)) || + ((level == 3) && (type == IEEE80211_FTYPE_DATA))) { + + ptr = skb->data; + + DBG_8723A("#############################\n"); + + for (i = 0; i < 64; i = i + 8) + DBG_8723A("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", + *(ptr + i), *(ptr + i + 1), *(ptr + i + 2), + *(ptr + i + 3), *(ptr + i + 4), + *(ptr + i + 5), *(ptr + i + 6), + *(ptr + i + 7)); + DBG_8723A("#############################\n"); + } +} + +static int validate_recv_frame(struct rtw_adapter *adapter, + struct recv_frame *precv_frame) +{ + /* shall check frame subtype, to / from ds, da, bssid */ + + /* then call check if rx seq/frag. duplicated. */ + u8 type; + u8 subtype; + int retval = _SUCCESS; + struct rx_pkt_attrib *pattrib = & precv_frame->attrib; + struct sk_buff *skb = precv_frame->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 ver; + u8 bDumpRxPkt; + u16 seq_ctrl, fctl; + + fctl = le16_to_cpu(hdr->frame_control); + ver = fctl & IEEE80211_FCTL_VERS; + type = fctl & IEEE80211_FCTL_FTYPE; + subtype = fctl & IEEE80211_FCTL_STYPE; + + /* add version chk */ + if (ver != 0) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("validate_recv_data_frame fail! (ver!= 0)\n")); + retval = _FAIL; + goto exit; + } + + pattrib->to_fr_ds = get_tofr_ds(hdr->frame_control); + + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); + pattrib->frag_num = seq_ctrl & IEEE80211_SCTL_FRAG; + pattrib->seq_num = seq_ctrl >> 4; + + pattrib->pw_save = ieee80211_has_pm(hdr->frame_control); + pattrib->mfrag = ieee80211_has_morefrags(hdr->frame_control); + pattrib->mdata = ieee80211_has_moredata(hdr->frame_control); + pattrib->privacy = ieee80211_has_protected(hdr->frame_control); + pattrib->order = ieee80211_has_order(hdr->frame_control); + + rtw_hal_get_def_var23a(adapter, HAL_DEF_DBG_DUMP_RXPKT, &bDumpRxPkt); + + if (unlikely(bDumpRxPkt == 1)) + dump_rx_pkt(skb, type, bDumpRxPkt); + + switch (type) + { + case IEEE80211_FTYPE_MGMT: + retval = validate_recv_mgnt_frame(adapter, precv_frame); + if (retval == _FAIL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("validate_recv_mgnt_frame fail\n")); + } + retval = _FAIL; /* only data frame return _SUCCESS */ + break; + case IEEE80211_FTYPE_CTL: + retval = validate_recv_ctrl_frame(adapter, precv_frame); + if (retval == _FAIL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("validate_recv_ctrl_frame fail\n")); + } + retval = _FAIL; /* only data frame return _SUCCESS */ + break; + case IEEE80211_FTYPE_DATA: + rtw_led_control(adapter, LED_CTL_RX); + pattrib->qos = (subtype & IEEE80211_STYPE_QOS_DATA) ? 1 : 0; + retval = validate_recv_data_frame(adapter, precv_frame); + if (retval == _FAIL) { + struct recv_priv *precvpriv = &adapter->recvpriv; + /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail\n")); */ + precvpriv->rx_drop++; + } + break; + default: + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("validate_recv_data_frame fail! type = 0x%x\n", type)); + retval = _FAIL; + break; + } + +exit: + return retval; +} + +/* remove the wlanhdr and add the eth_hdr */ + +static int wlanhdr_to_ethhdr (struct recv_frame *precvframe) +{ + u16 eth_type, len, hdrlen; + u8 bsnaphdr; + u8 *psnap; + + int ret = _SUCCESS; + struct rtw_adapter *adapter = precvframe->adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + struct sk_buff *skb = precvframe->pkt; + u8 *ptr; + struct rx_pkt_attrib *pattrib = &precvframe->attrib; + + + + ptr = skb->data; + hdrlen = pattrib->hdrlen; + psnap = ptr + hdrlen; + eth_type = (psnap[6] << 8) | psnap[7]; + /* convert hdr + possible LLC headers into Ethernet header */ + /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */ + if ((ether_addr_equal(psnap, rfc1042_header) && + eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || + ether_addr_equal(psnap, bridge_tunnel_header)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation + and replace EtherType */ + bsnaphdr = true; + hdrlen += SNAP_SIZE; + } else { + /* Leave Ethernet header part of hdr and full payload */ + bsnaphdr = false; + eth_type = (psnap[0] << 8) | psnap[1]; + } + + len = skb->len - hdrlen; + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("\n === pattrib->hdrlen: %x, pattrib->iv_len:%x ===\n\n", + pattrib->hdrlen, pattrib->iv_len)); + + pattrib->eth_type = eth_type; + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) { + ptr += hdrlen; + *ptr = 0x87; + *(ptr + 1) = 0x12; + + eth_type = 0x8712; + /* append rx status for mp test packets */ + + ptr = skb_pull(skb, (hdrlen - sizeof(struct ethhdr) + 2) - 24); + memcpy(ptr, skb->head, 24); + ptr += 24; + } else { + ptr = skb_pull(skb, (hdrlen - sizeof(struct ethhdr) + + (bsnaphdr ? 2:0))); + } + + ether_addr_copy(ptr, pattrib->dst); + ether_addr_copy(ptr + ETH_ALEN, pattrib->src); + + if (!bsnaphdr) { + len = htons(len); + memcpy(ptr + 12, &len, 2); + } + + + return ret; +} + +/* perform defrag */ +struct recv_frame *recvframe_defrag(struct rtw_adapter *adapter, + struct rtw_queue *defrag_q); +struct recv_frame *recvframe_defrag(struct rtw_adapter *adapter, + struct rtw_queue *defrag_q) +{ + struct list_head *plist, *phead, *ptmp; + u8 *data, wlanhdr_offset; + u8 curfragnum; + struct recv_frame *pnfhdr; + struct recv_frame *prframe, *pnextrframe; + struct rtw_queue *pfree_recv_queue; + struct sk_buff *skb; + + + + curfragnum = 0; + pfree_recv_queue = &adapter->recvpriv.free_recv_queue; + + phead = get_list_head(defrag_q); + plist = phead->next; + prframe = container_of(plist, struct recv_frame, list); + list_del_init(&prframe->list); + skb = prframe->pkt; + + if (curfragnum != prframe->attrib.frag_num) { + /* the first fragment number must be 0 */ + /* free the whole queue */ + rtw_free_recvframe23a(prframe, pfree_recv_queue); + rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue); + + return NULL; + } + + curfragnum++; + + phead = get_list_head(defrag_q); + + data = prframe->pkt->data; + + list_for_each_safe(plist, ptmp, phead) { + pnfhdr = container_of(plist, struct recv_frame, list); + pnextrframe = (struct recv_frame *)pnfhdr; + /* check the fragment sequence (2nd ~n fragment frame) */ + + if (curfragnum != pnfhdr->attrib.frag_num) { + /* the fragment number must be increasing + (after decache) */ + /* release the defrag_q & prframe */ + rtw_free_recvframe23a(prframe, pfree_recv_queue); + rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue); + return NULL; + } + + curfragnum++; + + /* copy the 2nd~n fragment frame's payload to the + first fragment */ + /* get the 2nd~last fragment frame's payload */ + + wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; + + skb_pull(pnfhdr->pkt, wlanhdr_offset); + + /* append to first fragment frame's tail + (if privacy frame, pull the ICV) */ + + skb_trim(skb, skb->len - prframe->attrib.icv_len); + + memcpy(skb_tail_pointer(skb), pnfhdr->pkt->data, + pnfhdr->pkt->len); + + skb_put(skb, pnfhdr->pkt->len); + + prframe->attrib.icv_len = pnfhdr->attrib.icv_len; + }; + + /* free the defrag_q queue and return the prframe */ + rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("Performance defrag!!!!!\n")); + + + + return prframe; +} + +/* check if need to defrag, if needed queue the frame to defrag_q */ +struct recv_frame* recvframe_chk_defrag23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + u8 ismfrag; + u8 fragnum; + u8 *psta_addr; + struct recv_frame *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv; + struct list_head *phead; + struct recv_frame *prtnframe = NULL; + struct rtw_queue *pfree_recv_queue, *pdefrag_q; + + + + pstapriv = &padapter->stapriv; + + pfhdr = precv_frame; + + pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + /* need to define struct of wlan header frame ctrl */ + ismfrag = pfhdr->attrib.mfrag; + fragnum = pfhdr->attrib.frag_num; + + psta_addr = pfhdr->attrib.ta; + psta = rtw_get_stainfo23a(pstapriv, psta_addr); + if (!psta) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) pfhdr->pkt->data; + if (!ieee80211_is_data(hdr->frame_control)) { + psta = rtw_get_bcmc_stainfo23a(padapter); + pdefrag_q = &psta->sta_recvpriv.defrag_q; + } else + pdefrag_q = NULL; + } else + pdefrag_q = &psta->sta_recvpriv.defrag_q; + + if ((ismfrag == 0) && (fragnum == 0)) { + prtnframe = precv_frame;/* isn't a fragment frame */ + } + + if (ismfrag == 1) { + /* 0~(n-1) fragment frame */ + /* enqueue to defraf_g */ + if (pdefrag_q != NULL) { + if (fragnum == 0) { + /* the first fragment */ + if (_rtw_queue_empty23a(pdefrag_q) == false) { + /* free current defrag_q */ + rtw_free_recvframe23a_queue(pdefrag_q, pfree_recv_queue); + } + } + + /* Then enqueue the 0~(n-1) fragment into the + defrag_q */ + + /* spin_lock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + list_add_tail(&pfhdr->list, phead); + /* spin_unlock(&pdefrag_q->lock); */ + + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("Enqueuq: ismfrag = %d, fragnum = %d\n", + ismfrag, fragnum)); + + prtnframe = NULL; + + } else { + /* can't find this ta's defrag_queue, + so free this recv_frame */ + rtw_free_recvframe23a(precv_frame, pfree_recv_queue); + prtnframe = NULL; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("Free because pdefrag_q == NULL: ismfrag = " + "%d, fragnum = %d\n", ismfrag, fragnum)); + } + } + + if ((ismfrag == 0) && (fragnum != 0)) { + /* the last fragment frame */ + /* enqueue the last fragment */ + if (pdefrag_q != NULL) { + /* spin_lock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + list_add_tail(&pfhdr->list, phead); + /* spin_unlock(&pdefrag_q->lock); */ + + /* call recvframe_defrag to defrag */ + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("defrag: ismfrag = %d, fragnum = %d\n", + ismfrag, fragnum)); + precv_frame = recvframe_defrag(padapter, pdefrag_q); + prtnframe = precv_frame; + } else { + /* can't find this ta's defrag_queue, + so free this recv_frame */ + rtw_free_recvframe23a(precv_frame, pfree_recv_queue); + prtnframe = NULL; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("Free because pdefrag_q == NULL: ismfrag = " + "%d, fragnum = %d\n", ismfrag, fragnum)); + } + + } + + if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) { + /* after defrag we must check tkip mic code */ + if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recvframe_chkmic(padapter, prtnframe) ==" + "_FAIL\n")); + rtw_free_recvframe23a(prtnframe, pfree_recv_queue); + prtnframe = NULL; + } + } + + + + return prtnframe; +} + +int amsdu_to_msdu(struct rtw_adapter *padapter, struct recv_frame *prframe); +int amsdu_to_msdu(struct rtw_adapter *padapter, struct recv_frame *prframe) +{ + struct rx_pkt_attrib *pattrib; + struct sk_buff *skb, *sub_skb; + struct sk_buff_head skb_list; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct rtw_queue *pfree_recv_queue = &precvpriv->free_recv_queue; + + pattrib = &prframe->attrib; + + skb = prframe->pkt; + skb_pull(skb, prframe->attrib.hdrlen); + __skb_queue_head_init(&skb_list); + + ieee80211_amsdu_to_8023s(skb, &skb_list, NULL, 0, 0, false); + + while (!skb_queue_empty(&skb_list)) { + sub_skb = __skb_dequeue(&skb_list); + + sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); + sub_skb->dev = padapter->pnetdev; + + sub_skb->ip_summed = CHECKSUM_NONE; + + netif_rx(sub_skb); + } + + prframe->pkt = NULL; + rtw_free_recvframe23a(prframe, pfree_recv_queue); + return _SUCCESS; +} + +int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num); +int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) +{ + u8 wsize = preorder_ctrl->wsize_b; + u16 wend = (preorder_ctrl->indicate_seq + wsize -1) & 0xFFF; + + /* Rx Reorder initialize condition. */ + if (preorder_ctrl->indicate_seq == 0xFFFF) + preorder_ctrl->indicate_seq = seq_num; + + /* Drop out the packet which SeqNum is smaller than WinStart */ + if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) + return false; + + /* */ + /* Sliding window manipulation. Conditions includes: */ + /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ + /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ + /* */ + if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { + preorder_ctrl->indicate_seq = + (preorder_ctrl->indicate_seq + 1) & 0xFFF; + } else if (SN_LESS(wend, seq_num)) { + /* boundary situation, when seq_num cross 0xFFF */ + if (seq_num >= (wsize - 1)) + preorder_ctrl->indicate_seq = seq_num + 1 -wsize; + else + preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; + } + return true; +} + +int enqueue_reorder_recvframe23a(struct recv_reorder_ctrl *preorder_ctrl, + struct recv_frame *prframe) +{ + struct rx_pkt_attrib *pattrib = &prframe->attrib; + struct rtw_queue *ppending_recvframe_queue; + struct list_head *phead, *plist, *ptmp; + struct recv_frame *hdr; + struct rx_pkt_attrib *pnextattrib; + + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + /* DbgPrint("+enqueue_reorder_recvframe23a()\n"); */ + + /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */ + /* spin_lock_ex(&ppending_recvframe_queue->lock); */ + + phead = get_list_head(ppending_recvframe_queue); + + list_for_each_safe(plist, ptmp, phead) { + hdr = container_of(plist, struct recv_frame, list); + pnextattrib = &hdr->attrib; + + if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) { + continue; + } else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) { + /* Duplicate entry is found!! Do not insert current entry. */ + /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ + + /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */ + return false; + } else { + break; + } + + /* DbgPrint("enqueue_reorder_recvframe23a():while\n"); */ + } + + /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */ + /* spin_lock_ex(&ppending_recvframe_queue->lock); */ + + list_del_init(&prframe->list); + + list_add_tail(&prframe->list, plist); + + /* spin_unlock_ex(&ppending_recvframe_queue->lock); */ + /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */ + + /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */ + return true; +} + +int recv_indicatepkts_in_order(struct rtw_adapter *padapter, + struct recv_reorder_ctrl *preorder_ctrl, + int bforced); +int recv_indicatepkts_in_order(struct rtw_adapter *padapter, + struct recv_reorder_ctrl *preorder_ctrl, + int bforced) +{ + /* u8 bcancelled; */ + struct list_head *phead, *plist; + struct recv_frame *prframe; + struct rx_pkt_attrib *pattrib; + /* u8 index = 0; */ + int bPktInBuf = false; + struct recv_priv *precvpriv; + struct rtw_queue *ppending_recvframe_queue; + + precvpriv = &padapter->recvpriv; + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + /* DbgPrint("+recv_indicatepkts_in_order\n"); */ + + /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */ + /* spin_lock_ex(&ppending_recvframe_queue->lock); */ + + phead = get_list_head(ppending_recvframe_queue); + plist = phead->next; + + /* Handling some condition for forced indicate case. */ + if (bforced) { + if (list_empty(phead)) { + /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */ + /* spin_unlock_ex(&ppending_recvframe_queue->lock); */ + return true; + } + + prframe = container_of(plist, struct recv_frame, list); + pattrib = &prframe->attrib; + preorder_ctrl->indicate_seq = pattrib->seq_num; + } + + /* Prepare indication list and indication. */ + /* Check if there is any packet need indicate. */ + while (!list_empty(phead)) { + + prframe = container_of(plist, struct recv_frame, list); + pattrib = &prframe->attrib; + + if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("recv_indicatepkts_in_order: indicate =%d " + "seq =%d amsdu =%d\n", + preorder_ctrl->indicate_seq, + pattrib->seq_num, pattrib->amsdu)); + + plist = plist->next; + list_del_init(&prframe->list); + + if (SN_EQUAL(preorder_ctrl->indicate_seq, + pattrib->seq_num)) { + preorder_ctrl->indicate_seq = + (preorder_ctrl->indicate_seq + 1)&0xFFF; + } + + if (!pattrib->amsdu) { + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + rtw_recv_indicatepkt23a(padapter, prframe); + } + } else { + if (amsdu_to_msdu(padapter, prframe) != + _SUCCESS) { + rtw_free_recvframe23a(prframe, + &precvpriv->free_recv_queue); + } + } + + /* Update local variables. */ + bPktInBuf = false; + + } else { + bPktInBuf = true; + break; + } + + /* DbgPrint("recv_indicatepkts_in_order():while\n"); */ + } + + /* spin_unlock_ex(&ppending_recvframe_queue->lock); */ + /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */ + + return bPktInBuf; +} + +int recv_indicatepkt_reorder(struct rtw_adapter *padapter, + struct recv_frame *prframe); +int recv_indicatepkt_reorder(struct rtw_adapter *padapter, + struct recv_frame *prframe) +{ + int retval = _SUCCESS; + struct rx_pkt_attrib *pattrib; + struct recv_reorder_ctrl *preorder_ctrl; + struct rtw_queue *ppending_recvframe_queue; + + pattrib = &prframe->attrib; + preorder_ctrl = prframe->preorder_ctrl; + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + + if (!pattrib->amsdu) { + /* s1. */ + wlanhdr_to_ethhdr(prframe); + + if ((pattrib->qos!= 1) || (pattrib->eth_type == 0x0806) || + (pattrib->ack_policy != 0)) { + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("@@@@ recv_indicatepkt_reorder -" + "recv_func recv_indicatepkt\n")); + + rtw_recv_indicatepkt23a(padapter, prframe); + return _SUCCESS; + } + + return _FAIL; + } + + if (preorder_ctrl->enable == false) { + /* indicate this recv_frame */ + preorder_ctrl->indicate_seq = pattrib->seq_num; + rtw_recv_indicatepkt23a(padapter, prframe); + + preorder_ctrl->indicate_seq = + (preorder_ctrl->indicate_seq + 1) % 4096; + return _SUCCESS; + } + } else { + /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ + if (preorder_ctrl->enable == false) { + preorder_ctrl->indicate_seq = pattrib->seq_num; + retval = amsdu_to_msdu(padapter, prframe); + + preorder_ctrl->indicate_seq = + (preorder_ctrl->indicate_seq + 1) % 4096; + return retval; + } + } + + spin_lock_bh(&ppending_recvframe_queue->lock); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("recv_indicatepkt_reorder: indicate =%d seq =%d\n", + preorder_ctrl->indicate_seq, pattrib->seq_num)); + + /* s2. check if winstart_b(indicate_seq) needs to been updated */ + if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) { + goto _err_exit; + } + + /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ + if (!enqueue_reorder_recvframe23a(preorder_ctrl, prframe)) { + goto _err_exit; + } + + /* s4. */ + /* Indication process. */ + /* After Packet dropping and Sliding Window shifting as above, + we can now just indicate the packets */ + /* with the SeqNum smaller than latest WinStart and buffer + other packets. */ + /* */ + /* For Rx Reorder condition: */ + /* 1. All packets with SeqNum smaller than WinStart => Indicate */ + /* 2. All packets with SeqNum larger than or equal to WinStart => + Buffer it. */ + /* */ + + if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false) == true) { + mod_timer(&preorder_ctrl->reordering_ctrl_timer, + jiffies + msecs_to_jiffies(REORDER_WAIT_TIME)); + spin_unlock_bh(&ppending_recvframe_queue->lock); + } else { + spin_unlock_bh(&ppending_recvframe_queue->lock); + del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); + } + return _SUCCESS; + +_err_exit: + + spin_unlock_bh(&ppending_recvframe_queue->lock); + return _FAIL; +} + +void rtw_reordering_ctrl_timeout_handler23a(unsigned long pcontext) +{ + struct recv_reorder_ctrl *preorder_ctrl; + struct rtw_adapter *padapter; + struct rtw_queue *ppending_recvframe_queue; + + preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; + padapter = preorder_ctrl->padapter; + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + + if (padapter->bDriverStopped || padapter->bSurpriseRemoved) { + return; + } + + /* DBG_8723A("+rtw_reordering_ctrl_timeout_handler23a() =>\n"); */ + + spin_lock_bh(&ppending_recvframe_queue->lock); + + if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true) { + mod_timer(&preorder_ctrl->reordering_ctrl_timer, + jiffies + msecs_to_jiffies(REORDER_WAIT_TIME)); + } + + spin_unlock_bh(&ppending_recvframe_queue->lock); +} + +int process_recv_indicatepkts(struct rtw_adapter *padapter, + struct recv_frame *prframe); +int process_recv_indicatepkts(struct rtw_adapter *padapter, + struct recv_frame *prframe) +{ + int retval = _SUCCESS; + /* struct recv_priv *precvpriv = &padapter->recvpriv; */ + /* struct rx_pkt_attrib *pattrib = &prframe->attrib; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if (phtpriv->ht_option == true) { /* B/G/N Mode */ + /* prframe->preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ + + /* including perform A-MPDU Rx Ordering Buffer Control */ + if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + retval = _FAIL; + return retval; + } + } + } else /* B/G mode */ + { + retval = wlanhdr_to_ethhdr(prframe); + if (retval != _SUCCESS) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("wlanhdr_to_ethhdr: drop pkt\n")); + return retval; + } + + if ((padapter->bDriverStopped == false) && + (padapter->bSurpriseRemoved == false)) { + /* indicate this recv_frame */ + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("@@@@ process_recv_indicatepkts- " + "recv_func recv_indicatepkt\n")); + rtw_recv_indicatepkt23a(padapter, prframe); + } else { + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("@@@@ process_recv_indicatepkts- " + "recv_func free_indicatepkt\n")); + + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, + ("recv_func:bDriverStopped(%d) OR " + "bSurpriseRemoved(%d)", + padapter->bDriverStopped, + padapter->bSurpriseRemoved)); + retval = _FAIL; + return retval; + } + + } + + return retval; +} + +static int recv_func_prehandle(struct rtw_adapter *padapter, + struct recv_frame *rframe) +{ + struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + int ret = _SUCCESS; + + /* check the frame crtl field and decache */ + ret = validate_recv_frame(padapter, rframe); + if (ret != _SUCCESS) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("recv_func: validate_recv_frame fail! drop pkt\n")); + rtw_free_recvframe23a(rframe, pfree_recv_queue); + goto exit; + } + +exit: + return ret; +} + +static int recv_func_posthandle(struct rtw_adapter *padapter, + struct recv_frame *prframe) +{ + int ret = _SUCCESS; + struct recv_frame *orig_prframe = prframe; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + /* DATA FRAME */ + rtw_led_control(padapter, LED_CTL_RX); + + prframe = decryptor(padapter, prframe); + if (prframe == NULL) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("decryptor: drop pkt\n")); + ret = _FAIL; + goto _recv_data_drop; + } + + prframe = recvframe_chk_defrag23a(padapter, prframe); + if (!prframe) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recvframe_chk_defrag23a: drop pkt\n")); + goto _recv_data_drop; + } + + /* + * Pull off crypto headers + */ + if (prframe->attrib.iv_len > 0) { + skb_pull(prframe->pkt, prframe->attrib.iv_len); + } + + if (prframe->attrib.icv_len > 0) { + skb_trim(prframe->pkt, + prframe->pkt->len - prframe->attrib.icv_len); + } + + prframe = portctrl(padapter, prframe); + if (!prframe) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("portctrl: drop pkt\n")); + ret = _FAIL; + goto _recv_data_drop; + } + + count_rx_stats(padapter, prframe, NULL); + + ret = process_recv_indicatepkts(padapter, prframe); + if (ret != _SUCCESS) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recv_func: process_recv_indicatepkts fail!\n")); + rtw_free_recvframe23a(orig_prframe, pfree_recv_queue);/* free this recv_frame */ + goto _recv_data_drop; + } + return ret; + +_recv_data_drop: + precvpriv->rx_drop++; + return ret; +} + +int rtw_recv_entry23a(struct recv_frame *rframe) +{ + int ret, r; + struct rtw_adapter *padapter = rframe->adapter; + struct rx_pkt_attrib *prxattrib = &rframe->attrib; + struct recv_priv *recvpriv = &padapter->recvpriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + + /* check if need to handle uc_swdec_pending_queue*/ + if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && + psecuritypriv->busetkipkey) { + struct recv_frame *pending_frame; + + while ((pending_frame = rtw_alloc_recvframe23a(&padapter->recvpriv.uc_swdec_pending_queue))) { + r = recv_func_posthandle(padapter, pending_frame); + if (r == _SUCCESS) + DBG_8723A("%s: dequeue uc_swdec_pending_queue\n", __func__); + } + } + + ret = recv_func_prehandle(padapter, rframe); + + if (ret == _SUCCESS) { + /* check if need to enqueue into uc_swdec_pending_queue*/ + if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && + !is_multicast_ether_addr(prxattrib->ra) && + prxattrib->encrypt > 0 && + (prxattrib->bdecrypted == 0) && + !is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) && + !psecuritypriv->busetkipkey) { + rtw_enqueue_recvframe23a(rframe, &padapter->recvpriv.uc_swdec_pending_queue); + DBG_8723A("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); + goto exit; + } + + ret = recv_func_posthandle(padapter, rframe); + + recvpriv->rx_pkts++; + } + +exit: + return ret; +} + +void rtw_signal_stat_timer_hdl23a(unsigned long data) +{ + struct rtw_adapter *adapter = (struct rtw_adapter *)data; + struct recv_priv *recvpriv = &adapter->recvpriv; + + u32 tmp_s, tmp_q; + u8 avg_signal_strength = 0; + u8 avg_signal_qual = 0; + u32 num_signal_strength = 0; + u32 num_signal_qual = 0; + u8 _alpha = 3; /* this value is based on converging_constant = 5000 */ + /* and sampling_interval = 1000 */ + + if (adapter->recvpriv.is_signal_dbg) { + /* update the user specific value, signal_strength_dbg, */ + /* to signal_strength, rssi */ + adapter->recvpriv.signal_strength = + adapter->recvpriv.signal_strength_dbg; + adapter->recvpriv.rssi = + (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); + } else { + if (recvpriv->signal_strength_data.update_req == 0) { + /* update_req is clear, means we got rx */ + avg_signal_strength = + recvpriv->signal_strength_data.avg_val; + num_signal_strength = + recvpriv->signal_strength_data.total_num; + /* after avg_vals are accquired, we can re-stat */ + /* the signal values */ + recvpriv->signal_strength_data.update_req = 1; + } + + if (recvpriv->signal_qual_data.update_req == 0) { + /* update_req is clear, means we got rx */ + avg_signal_qual = recvpriv->signal_qual_data.avg_val; + num_signal_qual = recvpriv->signal_qual_data.total_num; + /* after avg_vals are accquired, we can re-stat */ + /*the signal values */ + recvpriv->signal_qual_data.update_req = 1; + } + + /* update value of signal_strength, rssi, signal_qual */ + if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == + false) { + tmp_s = (avg_signal_strength + (_alpha - 1) * + recvpriv->signal_strength); + if (tmp_s %_alpha) + tmp_s = tmp_s / _alpha + 1; + else + tmp_s = tmp_s / _alpha; + if (tmp_s > 100) + tmp_s = 100; + + tmp_q = (avg_signal_qual + (_alpha - 1) * + recvpriv->signal_qual); + if (tmp_q %_alpha) + tmp_q = tmp_q / _alpha + 1; + else + tmp_q = tmp_q / _alpha; + if (tmp_q > 100) + tmp_q = 100; + + recvpriv->signal_strength = tmp_s; + recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); + recvpriv->signal_qual = tmp_q; + + DBG_8723A("%s signal_strength:%3u, rssi:%3d, " + "signal_qual:%3u, num_signal_strength:%u, " + "num_signal_qual:%u\n", + __func__, recvpriv->signal_strength, + recvpriv->rssi, recvpriv->signal_qual, + num_signal_strength, num_signal_qual + ); + } + } + rtw_set_signal_stat_timer(recvpriv); +} diff --git a/drivers/staging/rtl8723au/core/rtw_security.c b/drivers/staging/rtl8723au/core/rtw_security.c new file mode 100644 index 000000000000..0d457144fde7 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_security.c @@ -0,0 +1,1653 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_SECURITY_C_ + +#include +#include +#include +#include + +/* WEP related ===== */ + +#define CRC32_POLY 0x04c11db7 + +struct arc4context +{ + u32 x; + u32 y; + u8 state[256]; +}; + +static void arcfour_init(struct arc4context *parc4ctx, u8 * key, u32 key_len) +{ + u32 t, u; + u32 keyindex; + u32 stateindex; + u8 * state; + u32 counter; + + state = parc4ctx->state; + parc4ctx->x = 0; + parc4ctx->y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = (u8)counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) + { + t = state[counter]; + stateindex = (stateindex + key[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = (u8)t; + state[counter] = (u8)u; + if (++keyindex >= key_len) + keyindex = 0; + } + +} +static u32 arcfour_byte( struct arc4context *parc4ctx) +{ + u32 x; + u32 y; + u32 sx, sy; + u8 * state; + + state = parc4ctx->state; + x = (parc4ctx->x + 1) & 0xff; + sx = state[x]; + y = (sx + parc4ctx->y) & 0xff; + sy = state[y]; + parc4ctx->x = x; + parc4ctx->y = y; + state[y] = (u8)sx; + state[x] = (u8)sy; + + return state[(sx + sy) & 0xff]; +} + +static void arcfour_encrypt( struct arc4context *parc4ctx, + u8 * dest, + u8 * src, + u32 len) +{ + u32 i; + + for (i = 0; i < len; i++) + dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); + +} + +static int bcrc32initialized = 0; +static u32 crc32_table[256]; + +static u8 crc32_reverseBit(u8 data) +{ + u8 retval = ((data << 7) & 0x80) | ((data << 5) & 0x40) | + ((data << 3) & 0x20) | ((data << 1) & 0x10) | + ((data >> 1) & 0x08) | ((data >> 3) & 0x04) | + ((data >> 5) & 0x02) | ((data >> 7) & 0x01); + return retval; +} + +static void crc32_init(void) +{ + + if (bcrc32initialized == 1) + return; + else{ + int i, j; + u32 c; + u8 *p = (u8 *)&c, *p1; + u8 k; + + c = 0x12340000; + + for (i = 0; i < 256; ++i) + { + k = crc32_reverseBit((u8)i); + for (c = ((u32)k) << 24, j = 8; j > 0; --j) { + c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); + } + p1 = (u8 *)&crc32_table[i]; + + p1[0] = crc32_reverseBit(p[3]); + p1[1] = crc32_reverseBit(p[2]); + p1[2] = crc32_reverseBit(p[1]); + p1[3] = crc32_reverseBit(p[0]); + } + bcrc32initialized = 1; + } +} + +static u32 getcrc32(u8 *buf, int len) +{ + u8 *p; + u32 crc; + + if (bcrc32initialized == 0) crc32_init(); + + crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ + + for (p = buf; len > 0; ++p, --len) + crc = crc32_table[ (crc ^ *p) & 0xff] ^ (crc >> 8); + + return ~crc; /* transmit complement, per CRC-32 spec */ +} + +/* Need to consider the fragment situation */ +void rtw_wep_encrypt23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + /* exclude ICV */ + unsigned char crc[4]; + struct arc4context mycontext; + int curfragnum, length, index; + u32 keylength; + u8 *pframe, *payload, *iv; /* wepkey */ + u8 wepkey[16]; + u8 hw_hdr_offset = 0; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (!pxmitframe->buf_addr) + return; + + hw_hdr_offset = TXDESC_OFFSET; + + pframe = pxmitframe->buf_addr + hw_hdr_offset; + + /* start to encrypt each fragment */ + if ((pattrib->encrypt != _WEP40_) && (pattrib->encrypt != _WEP104_)) + return; + + index = psecuritypriv->dot11PrivacyKeyIndex; + keylength = psecuritypriv->dot11DefKeylen[index]; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags ; curfragnum++) { + iv = pframe + pattrib->hdrlen; + memcpy(&wepkey[0], iv, 3); + memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[index].skey[0], + keylength); + payload = pframe + pattrib->iv_len + pattrib->hdrlen; + + if ((curfragnum + 1) == pattrib->nr_frags) { + /* the last fragment */ + length = pattrib->last_txcmdsz - pattrib->hdrlen - + pattrib->iv_len- pattrib->icv_len; + + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); + + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + } else { + length = pxmitpriv->frag_len - pattrib->hdrlen - + pattrib->iv_len - pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((unsigned long)(pframe)); + } + } + +} + +void rtw_wep_decrypt23a(struct rtw_adapter *padapter, + struct recv_frame *precvframe) +{ + /* exclude ICV */ + u8 crc[4]; + struct arc4context mycontext; + int length; + u32 keylength; + u8 *pframe, *payload, *iv, wepkey[16]; + u8 keyindex; + struct rx_pkt_attrib *prxattrib = &precvframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sk_buff * skb = precvframe->pkt; + + pframe = skb->data; + + /* start to decrypt recvframe */ + if ((prxattrib->encrypt =! _WEP40_) && (prxattrib->encrypt != _WEP104_)) + return; + + iv = pframe + prxattrib->hdrlen; + /* keyindex = (iv[3]&0x3); */ + keyindex = prxattrib->key_index; + keylength = psecuritypriv->dot11DefKeylen[keyindex]; + memcpy(&wepkey[0], iv, 3); + /* memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); */ + memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], + keylength); + length = skb->len - prxattrib->hdrlen - prxattrib->iv_len; + + payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; + + /* decrypt payload include icv */ + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + + /* calculate icv and compare the icv */ + *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length - 4)); + + if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] || + crc[1] != payload[length - 3] || crc[0] != payload[length - 4]) { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("rtw_wep_decrypt23a:icv error crc[3](%x)!= payload" + "[length-1](%x) || crc[2](%x)!= payload[length-2](%x)" + " || crc[1](%x)!= payload[length-3](%x) || crc[0](%x)" + "!= payload[length-4](%x)\n", + crc[3], payload[length - 1], + crc[2], payload[length - 2], + crc[1], payload[length - 3], + crc[0], payload[length - 4])); + } + + return; +} + +/* 3 ===== TKIP related ===== */ + +static u32 secmicgetuint32(u8 * p) +/* Convert from Byte[] to u32 in a portable way */ +{ + s32 i; + u32 res = 0; + + for (i = 0; i<4; i++) + { + res |= ((u32)(*p++)) << (8*i); + } + + return res; +} + +static void secmicputuint32(u8 * p, u32 val) +/* Convert from long to Byte[] in a portable way */ +{ + long i; + + for (i = 0; i<4; i++) + { + *p++ = (u8) (val & 0xff); + val >>= 8; + } + +} + +static void secmicclear(struct mic_data *pmicdata) +{ +/* Reset the state to the empty message. */ + + pmicdata->L = pmicdata->K0; + pmicdata->R = pmicdata->K1; + pmicdata->nBytesInM = 0; + pmicdata->M = 0; + +} + +void rtw_secmicsetkey23a(struct mic_data *pmicdata, u8 * key) +{ + /* Set the key */ + + pmicdata->K0 = secmicgetuint32(key); + pmicdata->K1 = secmicgetuint32(key + 4); + /* and reset the message */ + secmicclear(pmicdata); + +} + +void rtw_secmicappend23abyte23a(struct mic_data *pmicdata, u8 b) +{ + + /* Append the byte to our word-sized buffer */ + pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM); + pmicdata->nBytesInM++; + /* Process the word if it is full. */ + if (pmicdata->nBytesInM >= 4) + { + pmicdata->L ^= pmicdata->M; + pmicdata->R ^= ROL32(pmicdata->L, 17); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROL32(pmicdata->L, 3); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROR32(pmicdata->L, 2); + pmicdata->L += pmicdata->R; + /* Clear the buffer */ + pmicdata->M = 0; + pmicdata->nBytesInM = 0; + } + +} + +void rtw_secmicappend23a(struct mic_data *pmicdata, u8 * src, u32 nbytes) +{ + + /* This is simple */ + while(nbytes > 0) + { + rtw_secmicappend23abyte23a(pmicdata, *src++); + nbytes--; + } + +} + +void rtw_secgetmic23a(struct mic_data *pmicdata, u8 * dst) +{ + + /* Append the minimum padding */ + rtw_secmicappend23abyte23a(pmicdata, 0x5a); + rtw_secmicappend23abyte23a(pmicdata, 0); + rtw_secmicappend23abyte23a(pmicdata, 0); + rtw_secmicappend23abyte23a(pmicdata, 0); + rtw_secmicappend23abyte23a(pmicdata, 0); + /* and then zeroes until the length is a multiple of 4 */ + while(pmicdata->nBytesInM != 0) + { + rtw_secmicappend23abyte23a(pmicdata, 0); + } + /* The appendByte function has already computed the result. */ + secmicputuint32(dst, pmicdata->L); + secmicputuint32(dst+4, pmicdata->R); + /* Reset to the empty message. */ + secmicclear(pmicdata); + +} + +void rtw_seccalctkipmic23a(u8 * key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri) +{ + + struct mic_data micdata; + u8 priority[4]={0x0, 0x0, 0x0, 0x0}; + + rtw_secmicsetkey23a(&micdata, key); + priority[0]= pri; + + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + if (header[1]&1) { /* ToDS == 1 */ + rtw_secmicappend23a(&micdata, &header[16], 6); /* DA */ + if (header[1]&2) /* From Ds == 1 */ + rtw_secmicappend23a(&micdata, &header[24], 6); + else + rtw_secmicappend23a(&micdata, &header[10], 6); + } + else{ /* ToDS == 0 */ + rtw_secmicappend23a(&micdata, &header[4], 6); /* DA */ + if (header[1]&2) /* From Ds == 1 */ + rtw_secmicappend23a(&micdata, &header[16], 6); + else + rtw_secmicappend23a(&micdata, &header[10], 6); + + } + rtw_secmicappend23a(&micdata, &priority[0], 4); + + rtw_secmicappend23a(&micdata, data, data_len); + + rtw_secgetmic23a(&micdata, mic_code); + +} + +/* macros for extraction/creation of unsigned char/unsigned short values */ +#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) +#define Lo8(v16) ((u8)((v16) & 0x00FF)) +#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) +#define Lo16(v32) ((u16)((v32) & 0xFFFF)) +#define Hi16(v32) ((u16)(((v32) >>16) & 0xFFFF)) +#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) + +/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ +#define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)]) + +/* S-box lookup: 16 bits --> 16 bits */ +#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) + +/* fixed algorithm "parameters" */ +#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ +#define TA_SIZE 6 /* 48-bit transmitter address */ +#define TK_SIZE 16 /* 128-bit temporal key */ +#define P1K_SIZE 10 /* 80-bit Phase1 key */ +#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ + +/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ +static const unsigned short Sbox1[2][256]= /* Sbox for hash (can be in ROM) */ +{ { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, + }, + + { /* second half of table is unsigned char-reversed version of first! */ + 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, + 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, + 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, + 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, + 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, + 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, + 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, + 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, + 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, + 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, + 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, + 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, + 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, + 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, + 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, + 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, + 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, + 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, + 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, + 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, + 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, + 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, + 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, + 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, + 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, + 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, + 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, + 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, + 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, + 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, + 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, + 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, + } +}; + + /* +********************************************************************** +* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 +* +* Inputs: +* tk[] = temporal key [128 bits] +* ta[] = transmitter's MAC address [ 48 bits] +* iv32 = upper 32 bits of IV [ 32 bits] +* Output: +* p1k[] = Phase 1 key [ 80 bits] +* +* Note: +* This function only needs to be called every 2**16 packets, +* although in theory it could be called every packet. +* +********************************************************************** +*/ +static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) +{ + int i; + + /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ + p1k[0] = Lo16(iv32); + p1k[1] = Hi16(iv32); + p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ + p1k[3] = Mk16(ta[3], ta[2]); + p1k[4] = Mk16(ta[5], ta[4]); + + /* Now compute an unbalanced Feistel cipher with 80-bit block */ + /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ + for (i = 0; i < PHASE1_LOOP_CNT ;i++) + { /* Each add operation here is mod 2**16 */ + p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0)); + p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2)); + p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4)); + p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6)); + p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0)); + p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ + } + +} + +/* +********************************************************************** +* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 +* +* Inputs: +* tk[] = Temporal key [128 bits] +* p1k[] = Phase 1 output key [ 80 bits] +* iv16 = low 16 bits of IV counter [ 16 bits] +* Output: +* rc4key[] = the key used to encrypt the packet [128 bits] +* +* Note: +* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique +* across all packets using the same key TK value. Then, for a +* given value of TK[], this TKIP48 construction guarantees that +* the final RC4KEY value is unique across all packets. +* +* Suggested implementation optimization: if PPK[] is "overlaid" +* appropriately on RC4KEY[], there is no need for the final +* for loop below that copies the PPK[] result into RC4KEY[]. +* +********************************************************************** +*/ +static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) +{ + int i; + u16 PPK[6]; /* temporary key for mixing */ + + /* Note: all adds in the PPK[] equations below are mod 2**16 */ + for (i = 0;i<5;i++) PPK[i]= p1k[i]; /* first, copy P1K to PPK */ + PPK[5] = p1k[4] +iv16; /* next, add in IV16 */ + + /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ + PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ + PPK[1] += _S_(PPK[0] ^ TK16(1)); + PPK[2] += _S_(PPK[1] ^ TK16(2)); + PPK[3] += _S_(PPK[2] ^ TK16(3)); + PPK[4] += _S_(PPK[3] ^ TK16(4)); + PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ + + /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ + PPK[0] += RotR1(PPK[5] ^ TK16(6)); + PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + /* Note: At this point, for a given key TK[0..15], the 96-bit output */ + /* value PPK[0..5] is guaranteed to be unique, as a function */ + /* of the 96-bit "input" value {TA, IV32, IV16}. That is, P1K */ + /* is now a keyed permutation of {TA, IV32, IV16}. */ + + /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ + rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ + rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ + rc4key[2] = Lo8(iv16); + rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); + + /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ + for (i = 0;i<6;i++) + { + rc4key[4+2*i] = Lo8(PPK[i]); + rc4key[5+2*i] = Hi8(PPK[i]); + } + +} + +/* The hlen isn't include the IV */ +u32 rtw_tkip_encrypt23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + u8 hw_hdr_offset = 0; + struct arc4context mycontext; + int curfragnum, length; + u32 prwskeylen; + + u8 *pframe, *payload,*iv,*prwskey; + union pn48 dot11txpn; + struct sta_info *stainfo; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u32 res = _SUCCESS; + + if (!pxmitframe->buf_addr) + return _FAIL; + + hw_hdr_offset = TXDESC_OFFSET; + + pframe = pxmitframe->buf_addr + hw_hdr_offset; + /* 4 start to encrypt each fragment */ + if (pattrib->encrypt == _TKIP_) { + + if (pattrib->psta) + { + stainfo = pattrib->psta; + } + else + { + DBG_8723A("%s, call rtw_get_stainfo()\n", __func__); + stainfo = rtw_get_stainfo23a(&padapter->stapriv, + &pattrib->ra[0]); + } + + if (stainfo!= NULL) { + + if (!(stainfo->state &_FW_LINKED)) + { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); + return _FAIL; + } + + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt23a: stainfo!= NULL!!!\n")); + + if (is_multicast_ether_addr(pattrib->ra)) + prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; + else + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + + prwskeylen = 16; + + for (curfragnum = 0;curfragnumnr_frags;curfragnum++) { + iv = pframe+pattrib->hdrlen; + payload = pframe+pattrib->iv_len+pattrib->hdrlen; + + GET_TKIP_PN(iv, dot11txpn); + + pnl = (u16)(dot11txpn.val); + pnh = (u32)(dot11txpn.val>>16); + + phase1((u16 *)&ttkey[0], prwskey,&pattrib->ta[0], pnh); + + phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl); + + if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */ + length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len; + RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("pattrib->iv_len =%x, pattrib->icv_len =%x\n", pattrib->iv_len, pattrib->icv_len)); + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));/* modified by Amy*/ + + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload+length, crc, 4); + + } + else{ + length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));/* modified by Amy*/ + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload+length, crc, 4); + + pframe+= pxmitpriv->frag_len; + pframe = (u8 *)RND4((unsigned long)(pframe)); + + } + } + + } + else{ + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt23a: stainfo == NULL!!!\n")); + DBG_8723A("%s, psta == NUL\n", __func__); + res = _FAIL; + } + + } + + return res; +} + +/* The hlen isn't include the IV */ +u32 rtw_tkip_decrypt23a(struct rtw_adapter *padapter, + struct recv_frame *precvframe) +{ + /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + struct arc4context mycontext; + int length; + u32 prwskeylen; + u8 *pframe, *payload,*iv,*prwskey; + union pn48 dot11txpn; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sk_buff * skb = precvframe->pkt; + u32 res = _SUCCESS; + + pframe = skb->data; + + /* 4 start to decrypt recvframe */ + if (prxattrib->encrypt == _TKIP_) { + + stainfo = rtw_get_stainfo23a(&padapter->stapriv, + &prxattrib->ta[0]); + if (stainfo!= NULL) { + + if (is_multicast_ether_addr(prxattrib->ra)) { + if (psecuritypriv->binstallGrpkey == false) { + res = _FAIL; + DBG_8723A("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); + goto exit; + } + prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + prwskeylen = 16; + } else { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt23a: stainfo!= NULL!!!\n")); + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + prwskeylen = 16; + } + + iv = pframe+prxattrib->hdrlen; + payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; + length = skb->len - prxattrib->hdrlen-prxattrib->iv_len; + + GET_TKIP_PN(iv, dot11txpn); + + pnl = (u16)(dot11txpn.val); + pnh = (u32)(dot11txpn.val>>16); + + phase1((u16 *)&ttkey[0], prwskey,&prxattrib->ta[0], pnh); + phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); + + /* 4 decrypt payload include icv */ + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + + *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4)); + + if (crc[3]!= payload[length-1] || crc[2]!= payload[length-2] || crc[1]!= payload[length-3] || crc[0]!= payload[length-4]) + { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_wep_decrypt23a:icv error crc[3](%x)!= payload[length-1](%x) || crc[2](%x)!= payload[length-2](%x) || crc[1](%x)!= payload[length-3](%x) || crc[0](%x)!= payload[length-4](%x)\n", + crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4])); + res = _FAIL; + } + } else { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt23a: stainfo == NULL!!!\n")); + res = _FAIL; + } + } +exit: + return res; +} + +/* 3 ===== AES related ===== */ + +#define MAX_MSG_SIZE 2048 +/*****************************/ +/******** SBOX Table *********/ +/*****************************/ + +static u8 sbox_table[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +/*****************************/ +/**** Function Prototypes ****/ +/*****************************/ + +static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, + int qc_exists); + +static void xor_128(u8 *a, u8 *b, u8 *out) +{ + int i; + + for (i = 0;i<16; i++) + out[i] = a[i] ^ b[i]; +} + +static void xor_32(u8 *a, u8 *b, u8 *out) +{ + int i; + + for (i = 0; i < 4; i++) + out[i] = a[i] ^ b[i]; +} + +static u8 sbox(u8 a) +{ + return sbox_table[(int)a]; +} + +static void next_key(u8 *key, int round) +{ + u8 rcon; + u8 sbox_key[4]; + u8 rcon_table[12] = + { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x1b, 0x36, 0x36, 0x36 + }; + + sbox_key[0] = sbox(key[13]); + sbox_key[1] = sbox(key[14]); + sbox_key[2] = sbox(key[15]); + sbox_key[3] = sbox(key[12]); + + rcon = rcon_table[round]; + + xor_32(&key[0], sbox_key, &key[0]); + key[0] = key[0] ^ rcon; + + xor_32(&key[4], &key[0], &key[4]); + xor_32(&key[8], &key[4], &key[8]); + xor_32(&key[12], &key[8], &key[12]); + +} + +static void byte_sub(u8 *in, u8 *out) +{ + int i; + + for (i = 0; i< 16; i++) + { + out[i] = sbox(in[i]); + } + +} + +static void shift_row(u8 *in, u8 *out) +{ + + out[0] = in[0]; + out[1] = in[5]; + out[2] = in[10]; + out[3] = in[15]; + out[4] = in[4]; + out[5] = in[9]; + out[6] = in[14]; + out[7] = in[3]; + out[8] = in[8]; + out[9] = in[13]; + out[10] = in[2]; + out[11] = in[7]; + out[12] = in[12]; + out[13] = in[1]; + out[14] = in[6]; + out[15] = in[11]; + +} + +static void mix_column(u8 *in, u8 *out) +{ + int i; + u8 add1b[4]; + u8 add1bf7[4]; + u8 rotl[4]; + u8 swap_halfs[4]; + u8 andf7[4]; + u8 rotr[4]; + u8 temp[4]; + u8 tempb[4]; + + for (i = 0 ; i<4; i++) + { + if ((in[i] & 0x80) == 0x80) + add1b[i] = 0x1b; + else + add1b[i] = 0x00; + } + + swap_halfs[0] = in[2]; /* Swap halfs */ + swap_halfs[1] = in[3]; + swap_halfs[2] = in[0]; + swap_halfs[3] = in[1]; + + rotl[0] = in[3]; /* Rotate left 8 bits */ + rotl[1] = in[0]; + rotl[2] = in[1]; + rotl[3] = in[2]; + + andf7[0] = in[0] & 0x7f; + andf7[1] = in[1] & 0x7f; + andf7[2] = in[2] & 0x7f; + andf7[3] = in[3] & 0x7f; + + for (i = 3; i>0; i--) /* logical shift left 1 bit */ + { + andf7[i] = andf7[i] << 1; + if ((andf7[i-1] & 0x80) == 0x80) + { + andf7[i] = (andf7[i] | 0x01); + } + } + andf7[0] = andf7[0] << 1; + andf7[0] = andf7[0] & 0xfe; + + xor_32(add1b, andf7, add1bf7); + + xor_32(in, add1bf7, rotr); + + temp[0] = rotr[0]; /* Rotate right 8 bits */ + rotr[0] = rotr[1]; + rotr[1] = rotr[2]; + rotr[2] = rotr[3]; + rotr[3] = temp[0]; + + xor_32(add1bf7, rotr, temp); + xor_32(swap_halfs, rotl, tempb); + xor_32(temp, tempb, out); + +} + +static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) +{ + int round; + int i; + u8 intermediatea[16]; + u8 intermediateb[16]; + u8 round_key[16]; + + for (i = 0; i<16; i++) round_key[i] = key[i]; + + for (round = 0; round < 11; round++) + { + if (round == 0) + { + xor_128(round_key, data, ciphertext); + next_key(round_key, round); + } + else if (round == 10) + { + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + xor_128(intermediateb, round_key, ciphertext); + } + else /* 1 - 9 */ + { + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + mix_column(&intermediateb[0], &intermediatea[0]); + mix_column(&intermediateb[4], &intermediatea[4]); + mix_column(&intermediateb[8], &intermediatea[8]); + mix_column(&intermediateb[12], &intermediatea[12]); + xor_128(intermediatea, round_key, ciphertext); + next_key(round_key, round); + } + } + +} + +/************************************************/ +/* construct_mic_iv() */ +/* Builds the MIC IV from header fields and PN */ +/************************************************/ +static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu, + uint payload_length, u8 *pn_vector) +{ + int i; + + mic_iv[0] = 0x59; + if (qc_exists && a4_exists) + mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ + if (qc_exists && !a4_exists) + mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ + if (!qc_exists) + mic_iv[1] = 0x00; + for (i = 2; i < 8; i++) + mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ + for (i = 8; i < 14; i++) + mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ + mic_iv[14] = (unsigned char)(payload_length / 256); + mic_iv[15] = (unsigned char)(payload_length % 256); +} + +/************************************************/ +/* construct_mic_header1() */ +/* Builds the first MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu) +{ + mic_header1[0] = (u8)((header_length - 2) / 256); + mic_header1[1] = (u8)((header_length - 2) % 256); + mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ + mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ + mic_header1[4] = mpdu[4]; /* A1 */ + mic_header1[5] = mpdu[5]; + mic_header1[6] = mpdu[6]; + mic_header1[7] = mpdu[7]; + mic_header1[8] = mpdu[8]; + mic_header1[9] = mpdu[9]; + mic_header1[10] = mpdu[10]; /* A2 */ + mic_header1[11] = mpdu[11]; + mic_header1[12] = mpdu[12]; + mic_header1[13] = mpdu[13]; + mic_header1[14] = mpdu[14]; + mic_header1[15] = mpdu[15]; + +} + +/************************************************/ + /* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_mic_header2( + u8 *mic_header2, + u8 *mpdu, + int a4_exists, + int qc_exists + ) +{ + int i; + + for (i = 0; i<16; i++) mic_header2[i]= 0x00; + + mic_header2[0] = mpdu[16]; /* A3 */ + mic_header2[1] = mpdu[17]; + mic_header2[2] = mpdu[18]; + mic_header2[3] = mpdu[19]; + mic_header2[4] = mpdu[20]; + mic_header2[5] = mpdu[21]; + + mic_header2[6] = 0x00; + mic_header2[7] = 0x00; /* mpdu[23]; */ + + if (!qc_exists && a4_exists) + { + for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ + + } + + if (qc_exists && !a4_exists) + { + mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ + mic_header2[9] = mpdu[25] & 0x00; + } + + if (qc_exists && a4_exists) + { + for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ + + mic_header2[14] = mpdu[30] & 0x0f; + mic_header2[15] = mpdu[31] & 0x00; + } + +} + +/************************************************/ +/* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, + u8 *mpdu, u8 *pn_vector, int c) +{ + int i = 0; + + for (i = 0; i<16; i++) ctr_preload[i] = 0x00; + i = 0; + + ctr_preload[0] = 0x01; /* flag */ + if (qc_exists && a4_exists) + ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ + if (qc_exists && !a4_exists) + ctr_preload[1] = mpdu[24] & 0x0f; + + for (i = 2; i < 8; i++) + ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ + for (i = 8; i < 14; i++) + ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ + ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */ + ctr_preload[15] = (unsigned char) (c % 256); + +} + +/************************************/ +/* bitwise_xor() */ +/* A 128 bit, bitwise exclusive or */ +/************************************/ +static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) +{ + int i; + + for (i = 0; i < 16; i++) + out[i] = ina[i] ^ inb[i]; +} + +static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) +{ + uint qc_exists, a4_exists, i, j, payload_remainder, + num_blocks, payload_index; + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; + u16 frsubtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; + + memset((void *)mic_iv, 0, 16); + memset((void *)mic_header1, 0, 16); + memset((void *)mic_header2, 0, 16); + memset((void *)ctr_preload, 0, 16); + memset((void *)chain_buffer, 0, 16); + memset((void *)aes_out, 0, 16); + memset((void *)padded_buffer, 0, 16); + + if ((hdrlen == sizeof(struct ieee80211_hdr_3addr) || + (hdrlen == sizeof(struct ieee80211_qos_hdr)))) + a4_exists = 0; + else + a4_exists = 1; + + if (ieee80211_is_data(hdr->frame_control)) { + if ((frsubtype == IEEE80211_STYPE_DATA_CFACK) || + (frsubtype == IEEE80211_STYPE_DATA_CFPOLL) || + (frsubtype == IEEE80211_STYPE_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != sizeof(struct ieee80211_qos_hdr)) + hdrlen += 2; + } else if ((frsubtype == IEEE80211_STYPE_QOS_DATA) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACK) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFPOLL) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACKPOLL)) { + if (hdrlen != sizeof(struct ieee80211_qos_hdr)) + hdrlen += 2; + qc_exists = 1; + } else { + qc_exists = 0; + } + } else { + qc_exists = 0; + } + pn_vector[0]= pframe[hdrlen]; + pn_vector[1]= pframe[hdrlen+1]; + pn_vector[2]= pframe[hdrlen+4]; + pn_vector[3]= pframe[hdrlen+5]; + pn_vector[4]= pframe[hdrlen+6]; + pn_vector[5]= pframe[hdrlen+7]; + + construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector); + + construct_mic_header1(mic_header1, hdrlen, pframe); + construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists); + + payload_remainder = plen % 16; + num_blocks = plen / 16; + + /* Find start of payload */ + payload_index = (hdrlen + 8); + + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index++]; + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + } + + for (j = 0; j < 8; j++) + mic[j] = aes_out[j]; + + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + pframe[payload_index+j] = mic[j]; + + payload_index = hdrlen + 8; + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, i+1); + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j]; + } + + if (payload_remainder > 0) { + /* If there is a short final block, then pad it, + * encrypt it and copy the unpadded part back + */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, + pn_vector, num_blocks+1); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index+j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder;j++) + pframe[payload_index++] = chain_buffer[j]; + } + + /* Encrypt the MIC */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, + pn_vector, 0); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) + padded_buffer[j] = pframe[j+hdrlen+8+plen]; + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8;j++) + pframe[payload_index++] = chain_buffer[j]; + + return _SUCCESS; +} + +u32 rtw_aes_encrypt23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ /* exclude ICV */ + /* Intermediate Buffers */ + int curfragnum, length; + u32 prwskeylen; + u8 *pframe, *prwskey; /* *payload,*iv */ + u8 hw_hdr_offset = 0; + struct sta_info *stainfo; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u32 res = _SUCCESS; + + if (!pxmitframe->buf_addr) + return _FAIL; + + hw_hdr_offset = TXDESC_OFFSET; + + pframe = pxmitframe->buf_addr + hw_hdr_offset; + + /* 4 start to encrypt each fragment */ + if (pattrib->encrypt != _AES_) + return _FAIL; + + if (pattrib->psta) { + stainfo = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + stainfo = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]); + } + + if (!stainfo) { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("rtw_aes_encrypt23a: stainfo == NULL!!!\n")); + DBG_8723A("%s, psta == NUL\n", __func__); + res = _FAIL; + goto out; + } + if (!(stainfo->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", + __func__, stainfo->state); + return _FAIL; + } + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("rtw_aes_encrypt23a: stainfo!= NULL!!!\n")); + + if (is_multicast_ether_addr(pattrib->ra)) + prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; + else + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + + prwskeylen = 16; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { + /* 4 the last fragment */ + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz - + pattrib->hdrlen-pattrib->iv_len - + pattrib->icv_len; + + aes_cipher(prwskey, pattrib->hdrlen, pframe, length); + } else { + length = pxmitpriv->frag_len-pattrib->hdrlen - + pattrib->iv_len - pattrib->icv_len; + + aes_cipher(prwskey, pattrib->hdrlen, pframe, length); + pframe += pxmitpriv->frag_len; + pframe = (u8*)RND4((unsigned long)pframe); + } + } +out: + return res; +} + +static int aes_decipher(u8 *key, uint hdrlen, + u8 *pframe, uint plen) +{ + static u8 message[MAX_MSG_SIZE]; + uint qc_exists, a4_exists, i, j, payload_remainder, + num_blocks, payload_index; + int res = _SUCCESS; + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe; + u16 frsubtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; + + memset((void *)mic_iv, 0, 16); + memset((void *)mic_header1, 0, 16); + memset((void *)mic_header2, 0, 16); + memset((void *)ctr_preload, 0, 16); + memset((void *)chain_buffer, 0, 16); + memset((void *)aes_out, 0, 16); + memset((void *)padded_buffer, 0, 16); + + /* start to decrypt the payload */ + + num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */ + + payload_remainder = (plen-8) % 16; + + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen+1]; + pn_vector[2] = pframe[hdrlen+4]; + pn_vector[3] = pframe[hdrlen+5]; + pn_vector[4] = pframe[hdrlen+6]; + pn_vector[5] = pframe[hdrlen+7]; + + if ((hdrlen == sizeof(struct ieee80211_hdr_3addr) || + (hdrlen == sizeof(struct ieee80211_qos_hdr)))) + a4_exists = 0; + else + a4_exists = 1; + + if (ieee80211_is_data(hdr->frame_control)) { + if ((frsubtype == IEEE80211_STYPE_DATA_CFACK) || + (frsubtype == IEEE80211_STYPE_DATA_CFPOLL) || + (frsubtype == IEEE80211_STYPE_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != sizeof(struct ieee80211_hdr_3addr)) + hdrlen += 2; + } else if ((frsubtype == IEEE80211_STYPE_QOS_DATA) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACK) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFPOLL) || + (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACKPOLL)) { + if (hdrlen != sizeof(struct ieee80211_hdr_3addr)) + hdrlen += 2; + qc_exists = 1; + } else { + qc_exists = 0; + } + } else { + qc_exists = 0; + } + + /* now, decrypt pframe with hdrlen offset and plen long */ + + payload_index = hdrlen + 8; /* 8 is for extiv */ + + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + pframe, pn_vector, i+1); + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j]; + } + + if (payload_remainder > 0) { + /* If there is a short final block, then pad it, + * encrypt it and copy the unpadded part back + */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, + pn_vector, num_blocks+1); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index+j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + pframe[payload_index++] = chain_buffer[j]; + } + + /* start to calculate the mic */ + if ((hdrlen +plen+8) <= MAX_MSG_SIZE) + memcpy(message, pframe, (hdrlen+plen+8)); /* 8 is for ext iv len */ + + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen+1]; + pn_vector[2] = pframe[hdrlen+4]; + pn_vector[3] = pframe[hdrlen+5]; + pn_vector[4] = pframe[hdrlen+6]; + pn_vector[5] = pframe[hdrlen+7]; + + construct_mic_iv(mic_iv, qc_exists, a4_exists, message, + plen-8, pn_vector); + + construct_mic_header1(mic_header1, hdrlen, message); + construct_mic_header2(mic_header2, message, a4_exists, qc_exists); + + payload_remainder = (plen-8) % 16; + num_blocks = (plen-8) / 16; + + /* Find start of payload */ + payload_index = (hdrlen + 8); + + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index++]; + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + } + + for (j = 0 ; j < 8; j++) + mic[j] = aes_out[j]; + + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + message[payload_index+j] = mic[j]; + + payload_index = hdrlen + 8; + for (i = 0; i< num_blocks; i++) { + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + message, pn_vector, i+1); + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + message[payload_index++] = chain_buffer[j]; + } + + if (payload_remainder > 0) { + /* If there is a short final block, then pad it, + * encrypt it and copy the unpadded part back + */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, + message, pn_vector, num_blocks+1); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index+j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + message[payload_index++] = chain_buffer[j]; + } + + /* Encrypt the MIC */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, + pn_vector, 0); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) + padded_buffer[j] = message[j+hdrlen+8+plen-8]; + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8; j++) + message[payload_index++] = chain_buffer[j]; + + /* compare the mic */ + for (i = 0; i < 8; i++) { + if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n", + i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i])); + DBG_8723A("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n", + i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]); + res = _FAIL; + } + } + return res; +} + +u32 rtw_aes_decrypt23a(struct rtw_adapter *padapter, struct recv_frame *precvframe) +{ /* exclude ICV */ + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sk_buff *skb = precvframe->pkt; + int length; + u8 *pframe, *prwskey; /* *payload,*iv */ + u32 res = _SUCCESS; + + pframe = skb->data; + /* 4 start to encrypt each fragment */ + if (!prxattrib->encrypt != _AES_) + return _FAIL; + + stainfo = rtw_get_stainfo23a(&padapter->stapriv, &prxattrib->ta[0]); + if (!stainfo) { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("rtw_aes_encrypt23a: stainfo == NULL!!!\n")); + res = _FAIL; + goto exit; + } + + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("rtw_aes_decrypt23a: stainfo!= NULL!!!\n")); + + if (is_multicast_ether_addr(prxattrib->ra)) { + /* in concurrent we should use sw decrypt in group key, + so we remove this message */ + if (!psecuritypriv->binstallGrpkey) { + res = _FAIL; + DBG_8723A("%s:rx bc/mc packets, but didn't install " + "group key!!!!!!!!!!\n", __func__); + goto exit; + } + prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { + DBG_8723A("not match packet_index =%d, install_index =" + "%d\n", prxattrib->key_index, + psecuritypriv->dot118021XGrpKeyid); + res = _FAIL; + goto exit; + } + } else { + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + } + + length = skb->len - prxattrib->hdrlen - prxattrib->iv_len; + + res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); +exit: + return res; +} + +void rtw_use_tkipkey_handler23a(void *FunctionContext) +{ + struct rtw_adapter *padapter = (struct rtw_adapter *)FunctionContext; + + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler23a ^^^\n")); + padapter->securitypriv.busetkipkey = true; + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + ("^^^rtw_use_tkipkey_handler23a padapter->securitypriv.busetkipkey =%d^^^\n", + padapter->securitypriv.busetkipkey)); +} diff --git a/drivers/staging/rtl8723au/core/rtw_sreset.c b/drivers/staging/rtl8723au/core/rtw_sreset.c new file mode 100644 index 000000000000..8d1a6fe168ac --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_sreset.c @@ -0,0 +1,253 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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 + +void sreset_init_value23a(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + mutex_init(&psrtpriv->silentreset_mutex); + psrtpriv->silent_reset_inprogress = false; + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + psrtpriv->last_tx_time = 0; + psrtpriv->last_tx_complete_time = 0; +} +void sreset_reset_value23a(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + psrtpriv->silent_reset_inprogress = false; + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + psrtpriv->last_tx_time = 0; + psrtpriv->last_tx_complete_time = 0; +} + +u8 sreset_get_wifi_status23a(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + u8 status = WIFI_STATUS_SUCCESS; + u32 val32 = 0; + + if (psrtpriv->silent_reset_inprogress) + return status; + val32 = rtw_read32(padapter, REG_TXDMA_STATUS); + if (val32 == 0xeaeaeaea) { + psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST; + } else if (val32 != 0) { + DBG_8723A("txdmastatu(%x)\n", val32); + psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR; + } + + if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) { + DBG_8723A("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status); + status = (psrtpriv->Wifi_Error_Status &~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL)); + } + DBG_8723A("==> %s wifi_status(0x%x)\n", __func__, status); + + /* status restore */ + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + + return status; +} + +void sreset_set_wifi_error_status23a(struct rtw_adapter *padapter, u32 status) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->srestpriv.Wifi_Error_Status = status; +} + +void sreset_set_trigger_point(struct rtw_adapter *padapter, s32 tgp) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->srestpriv.dbg_trigger_point = tgp; +} + +bool sreset_inprogress(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + return pHalData->srestpriv.silent_reset_inprogress; +} + +static void sreset_restore_security_station(struct rtw_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info; + u8 val8; + + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) + val8 = 0xcc; + else + val8 = 0xcf; + rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + psta = rtw_get_stainfo23a(pstapriv, get_bssid(mlmepriv)); + if (psta == NULL) { + /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ + } else { + /* pairwise key */ + rtw_setstakey_cmd23a(padapter, (unsigned char *)psta, true); + /* group key */ + rtw_set_key23a(padapter,&padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0); + } + } +} + +static void sreset_restore_network_station(struct rtw_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 threshold; + + rtw_setopmode_cmd23a(padapter, Ndis802_11Infrastructure); + + /* TH = 1 => means that invalidate usb rx aggregation */ + /* TH = 0 => means that validate usb rx aggregation, use init value. */ + if (mlmepriv->htpriv.ht_option) { + if (padapter->registrypriv.wifi_spec == 1) + threshold = 1; + else + threshold = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } else { + threshold = 1; + rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } + + set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + /* disable dynamic functions, such as high power, DIG */ + /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */ + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); + + { + u8 join_type = 0; + rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + } + + Set_MSR23a(padapter, (pmlmeinfo->state & 0x3)); + + mlmeext_joinbss_event_callback23a(padapter, 1); + /* restore Sequence No. */ + rtw_write8(padapter, 0x4dc, padapter->xmitpriv.nqos_ssn); + + sreset_restore_security_station(padapter); +} + +static void sreset_restore_network_status(struct rtw_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + + if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { + DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + sreset_restore_network_station(padapter); + } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { + DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + rtw_ap_restore_network(padapter); + } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) { + DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + } else { + DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + } +} + +static void sreset_stop_adapter(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter == NULL) + return; + + DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + if (!rtw_netif_queue_stopped(padapter->pnetdev)) + netif_tx_stop_all_queues(padapter->pnetdev); + + rtw_cancel_all_timer23a(padapter); + + /* TODO: OS and HCI independent */ + tasklet_kill(&pxmitpriv->xmit_tasklet); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + rtw_scan_abort23a(padapter); + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) + rtw23a_join_to_handler((unsigned long)padapter); +} + +static void sreset_start_adapter(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter == NULL) + return; + + DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + sreset_restore_network_status(padapter); + } + + /* TODO: OS and HCI independent */ + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); + + mod_timer(&padapter->mlmepriv.dynamic_chk_timer, + jiffies + msecs_to_jiffies(2000)); + + if (rtw_netif_queue_stopped(padapter->pnetdev)) + netif_tx_wake_all_queues(padapter->pnetdev); +} + +void sreset_reset(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + unsigned long start = jiffies; + + DBG_8723A("%s\n", __func__); + + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + + mutex_lock(&psrtpriv->silentreset_mutex); + psrtpriv->silent_reset_inprogress = true; + pwrpriv->change_rfpwrstate = rf_off; + + sreset_stop_adapter(padapter); + + ips_enter23a(padapter); + ips_leave23a(padapter); + + sreset_start_adapter(padapter); + psrtpriv->silent_reset_inprogress = false; + mutex_unlock(&psrtpriv->silentreset_mutex); + + DBG_8723A("%s done in %d ms\n", __func__, + jiffies_to_msecs(jiffies - start)); +} diff --git a/drivers/staging/rtl8723au/core/rtw_sta_mgt.c b/drivers/staging/rtl8723au/core/rtw_sta_mgt.c new file mode 100644 index 000000000000..451b58f47287 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_sta_mgt.c @@ -0,0 +1,509 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_STA_MGT_C_ + +#include +#include +#include +#include +#include +#include + +void _rtw_init_stainfo(struct sta_info *psta) +{ + memset((u8 *)psta, 0, sizeof (struct sta_info)); + spin_lock_init(&psta->lock); + INIT_LIST_HEAD(&psta->list); + INIT_LIST_HEAD(&psta->hash_list); + _rtw_init_queue23a(&psta->sleep_q); + psta->sleepq_len = 0; + _rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv); + _rtw_init_sta_recv_priv23a(&psta->sta_recvpriv); +#ifdef CONFIG_8723AU_AP_MODE + INIT_LIST_HEAD(&psta->asoc_list); + INIT_LIST_HEAD(&psta->auth_list); + psta->expire_to = 0; + psta->flags = 0; + psta->capability = 0; + psta->bpairwise_key_installed = false; + psta->nonerp_set = 0; + psta->no_short_slot_time_set = 0; + psta->no_short_preamble_set = 0; + psta->no_ht_gf_set = 0; + psta->no_ht_set = 0; + psta->ht_20mhz_set = 0; + psta->keep_alive_trycnt = 0; +#endif /* CONFIG_8723AU_AP_MODE */ +} + +u32 _rtw_init_sta_priv23a(struct sta_priv *pstapriv) +{ + struct sta_info *psta; + s32 i; + + pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA+ 4); + + if (!pstapriv->pallocated_stainfo_buf) + return _FAIL; + + pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - + ((unsigned long)(pstapriv->pallocated_stainfo_buf) & 3); + _rtw_init_queue23a(&pstapriv->free_sta_queue); + spin_lock_init(&pstapriv->sta_hash_lock); + pstapriv->asoc_sta_count = 0; + _rtw_init_queue23a(&pstapriv->sleep_q); + _rtw_init_queue23a(&pstapriv->wakeup_q); + psta = (struct sta_info *)(pstapriv->pstainfo_buf); + + for (i = 0; i < NUM_STA; i++) { + _rtw_init_stainfo(psta); + INIT_LIST_HEAD(&pstapriv->sta_hash[i]); + list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); + psta++; + } +#ifdef CONFIG_8723AU_AP_MODE + pstapriv->sta_dz_bitmap = 0; + pstapriv->tim_bitmap = 0; + INIT_LIST_HEAD(&pstapriv->asoc_list); + INIT_LIST_HEAD(&pstapriv->auth_list); + spin_lock_init(&pstapriv->asoc_list_lock); + spin_lock_init(&pstapriv->auth_list_lock); + pstapriv->asoc_list_cnt = 0; + pstapriv->auth_list_cnt = 0; + pstapriv->auth_to = 3; /* 3*2 = 6 sec */ + pstapriv->assoc_to = 3; + /* pstapriv->expire_to = 900; 900*2 = 1800 sec = 30 min, expire after no any traffic. */ + /* pstapriv->expire_to = 30; 30*2 = 60 sec = 1 min, expire after no any traffic. */ + pstapriv->expire_to = 3; /* 3*2 = 6 sec */ + pstapriv->max_num_sta = NUM_STA; +#endif + return _SUCCESS; +} + +inline int rtw_stainfo_offset23a(struct sta_priv *stapriv, struct sta_info *sta) +{ + int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); + + if (!stainfo_offset_valid(offset)) + DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset); + return offset; +} + +inline struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv, int offset) +{ + if (!stainfo_offset_valid(offset)) + DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset); + return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); +} + +/* this function is used to free the memory of lock || sema for all stainfos */ +void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) +{ + struct list_head *plist, *phead; + struct sta_info *psta; + + spin_lock_bh(&pstapriv->sta_hash_lock); + + phead = get_list_head(&pstapriv->free_sta_queue); + + /* we really achieve a lot in this loop .... */ + list_for_each(plist, phead) + psta = container_of(plist, struct sta_info, list); + spin_unlock_bh(&pstapriv->sta_hash_lock); +} + +void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) +{ + rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ +} + +u32 _rtw_free_sta_priv23a(struct sta_priv *pstapriv) +{ + struct list_head *phead, *plist, *ptmp; + struct sta_info *psta; + struct recv_reorder_ctrl *preorder_ctrl; + int index; + + if (pstapriv) { + /* delete all reordering_ctrl_timer */ + spin_lock_bh(&pstapriv->sta_hash_lock); + for (index = 0; index < NUM_STA; index++) { + phead = &pstapriv->sta_hash[index]; + + list_for_each_safe(plist, ptmp, phead) { + int i; + psta = container_of(plist, struct sta_info, + hash_list); + for (i = 0; i < 16 ; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); + } + } + } + spin_unlock_bh(&pstapriv->sta_hash_lock); + /*===============================*/ + + rtw_mfree_sta_priv_lock(pstapriv); + + if (pstapriv->pallocated_stainfo_buf) + rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4); + } + return _SUCCESS; +} + +struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr) +{ + struct list_head *phash_list; + struct sta_info *psta; + struct rtw_queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + uint tmp_aid; + s32 index; + int i = 0; + u16 wRxSeqInitialValue = 0xffff; + + pfree_sta_queue = &pstapriv->free_sta_queue; + + spin_lock_bh(&pstapriv->sta_hash_lock); + + if (_rtw_queue_empty23a(pfree_sta_queue)) { + spin_unlock_bh(&pstapriv->sta_hash_lock); + return NULL; + } + psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list); + + list_del_init(&psta->list); + + tmp_aid = psta->aid; + + _rtw_init_stainfo(psta); + + psta->padapter = pstapriv->padapter; + + memcpy(psta->hwaddr, hwaddr, ETH_ALEN); + + index = wifi_mac_hash(hwaddr); + + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, + ("rtw_alloc_stainfo23a: index = %x", index)); + if (index >= NUM_STA) { + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, + ("ERROR => rtw_alloc_stainfo23a: index >= NUM_STA")); + psta = NULL; + goto exit; + } + phash_list = &pstapriv->sta_hash[index]; + + list_add_tail(&psta->hash_list, phash_list); + + pstapriv->asoc_sta_count ++ ; + +/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ +/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ +/* So, we initialize the tid_rxseq variable as the 0xffff. */ + + for (i = 0; i < 16; i++) + memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); + + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, + ("alloc number_%d stainfo with hwaddr = %pM\n", + pstapriv->asoc_sta_count, hwaddr)); + + init_addba_retry_timer23a(psta); + + /* for A-MPDU Rx reordering buffer control */ + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + + preorder_ctrl->padapter = pstapriv->padapter; + + preorder_ctrl->enable = false; + + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */ + preorder_ctrl->wsize_b = 64;/* 64; */ + + _rtw_init_queue23a(&preorder_ctrl->pending_recvframe_queue); + + rtw_init_recv_timer23a(preorder_ctrl); + } + /* init for DM */ + psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); + psta->rssi_stat.UndecoratedSmoothedCCK = (-1); + + /* init for the sequence number of received management frame */ + psta->RxMgmtFrameSeqNum = 0xffff; +exit: + spin_unlock_bh(&pstapriv->sta_hash_lock); + return psta; +} + +/* using pstapriv->sta_hash_lock to protect */ +u32 rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct rtw_queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_xmit_priv *pstaxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct hw_xmit *phwxmit; + int i; + + if (psta == NULL) + goto exit; + + spin_lock_bh(&psta->lock); + psta->state &= ~_FW_LINKED; + spin_unlock_bh(&psta->lock); + + pfree_sta_queue = &pstapriv->free_sta_queue; + + pstaxmitpriv = &psta->sta_xmitpriv; + + spin_lock_bh(&pxmitpriv->lock); + + rtw_free_xmitframe_queue23a(pxmitpriv, &psta->sleep_q); + psta->sleepq_len = 0; + + /* vo */ + rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); + list_del_init(&pstaxmitpriv->vo_q.tx_pending); + phwxmit = pxmitpriv->hwxmits; + phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt; + pstaxmitpriv->vo_q.qcnt = 0; + + /* vi */ + rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); + list_del_init(&pstaxmitpriv->vi_q.tx_pending); + phwxmit = pxmitpriv->hwxmits+1; + phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt; + pstaxmitpriv->vi_q.qcnt = 0; + + /* be */ + rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); + list_del_init(&pstaxmitpriv->be_q.tx_pending); + phwxmit = pxmitpriv->hwxmits+2; + phwxmit->accnt -= pstaxmitpriv->be_q.qcnt; + pstaxmitpriv->be_q.qcnt = 0; + + /* bk */ + rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); + list_del_init(&pstaxmitpriv->bk_q.tx_pending); + phwxmit = pxmitpriv->hwxmits+3; + phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt; + pstaxmitpriv->bk_q.qcnt = 0; + + spin_unlock_bh(&pxmitpriv->lock); + + list_del_init(&psta->hash_list); + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", pstapriv->asoc_sta_count, psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5])); + pstapriv->asoc_sta_count --; + + /* re-init sta_info; 20061114 will be init in alloc_stainfo */ + /* _rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv); */ + /* _rtw_init_sta_recv_priv23a(&psta->sta_recvpriv); */ + + del_timer_sync(&psta->addba_retry_timer); + + /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ + for (i = 0; i < 16; i++) { + struct list_head *phead, *plist; + struct recv_frame *prframe; + struct rtw_queue *ppending_recvframe_queue; + struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + preorder_ctrl = &psta->recvreorder_ctrl[i]; + + del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); + + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + + spin_lock_bh(&ppending_recvframe_queue->lock); + phead = get_list_head(ppending_recvframe_queue); + plist = phead->next; + + while (!list_empty(phead)) { + prframe = container_of(plist, struct recv_frame, list); + plist = plist->next; + list_del_init(&prframe->list); + rtw_free_recvframe23a(prframe, pfree_recv_queue); + } + spin_unlock_bh(&ppending_recvframe_queue->lock); + } + if (!(psta->state & WIFI_AP_STATE)) + rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, false); +#ifdef CONFIG_8723AU_AP_MODE + spin_lock_bh(&pstapriv->auth_list_lock); + if (!list_empty(&psta->auth_list)) { + list_del_init(&psta->auth_list); + pstapriv->auth_list_cnt--; + } + spin_unlock_bh(&pstapriv->auth_list_lock); + + psta->expire_to = 0; + + psta->sleepq_ac_len = 0; + psta->qos_info = 0; + + psta->max_sp_len = 0; + psta->uapsd_bk = 0; + psta->uapsd_be = 0; + psta->uapsd_vi = 0; + psta->uapsd_vo = 0; + + psta->has_legacy_ac = 0; + + pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid); + pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); + + if ((psta->aid >0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) { + pstapriv->sta_aid[psta->aid - 1] = NULL; + psta->aid = 0; + } +#endif /* CONFIG_8723AU_AP_MODE */ + list_add_tail(&psta->list, get_list_head(pfree_sta_queue)); +exit: + return _SUCCESS; +} + +/* free all stainfo which in sta_hash[all] */ +void rtw_free_all_stainfo23a(struct rtw_adapter *padapter) +{ + struct list_head *plist, *phead, *ptmp; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info* pbcmc_stainfo = rtw_get_bcmc_stainfo23a(padapter); + s32 index; if (pstapriv->asoc_sta_count == 1) + return; + + spin_lock_bh(&pstapriv->sta_hash_lock); + + for (index = 0; index < NUM_STA; index++) { + phead = &pstapriv->sta_hash[index]; + + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, hash_list); + + if (pbcmc_stainfo!= psta) + rtw_free_stainfo23a(padapter, psta); + } + } + spin_unlock_bh(&pstapriv->sta_hash_lock); +} + +/* any station allocated can be searched by hash list */ +struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr) +{ + struct list_head *plist, *phead; + struct sta_info *psta = NULL; + u32 index; + u8 *addr; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if (hwaddr == NULL) + return NULL; + + if (is_multicast_ether_addr(hwaddr)) + addr = bc_addr; + else + addr = hwaddr; + + index = wifi_mac_hash(addr); + + spin_lock_bh(&pstapriv->sta_hash_lock); + + phead = &pstapriv->sta_hash[index]; + + list_for_each(plist, phead) { + psta = container_of(plist, struct sta_info, hash_list); + + if (!memcmp(psta->hwaddr, addr, ETH_ALEN)) { + /* if found the matched address */ + break; + } + psta = NULL; + } + spin_unlock_bh(&pstapriv->sta_hash_lock); + return psta; +} + +u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter* padapter) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct tx_servq *ptxservq; + u32 res = _SUCCESS; + unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + psta = rtw_alloc_stainfo23a(pstapriv, bcast_addr); + if (psta == NULL) { + res = _FAIL; + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, + ("rtw_alloc_stainfo23a fail")); + return res; + } + /* default broadcast & multicast use macid 1 */ + psta->mac_id = 1; + + ptxservq = &psta->sta_xmitpriv.be_q; + return _SUCCESS; +} + +struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter) +{ + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + psta = rtw_get_stainfo23a(pstapriv, bc_addr); + return psta; +} + +u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr) +{ + u8 res = true; +#ifdef CONFIG_8723AU_AP_MODE + struct list_head *plist, *phead; + struct rtw_wlan_acl_node *paclnode; + u8 match = false; + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; + struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q; + + spin_lock_bh(&pacl_node_q->lock); + phead = get_list_head(pacl_node_q); + + list_for_each(plist, phead) { + paclnode = container_of(plist, struct rtw_wlan_acl_node, list); + + if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) { + if (paclnode->valid) { + match = true; + break; + } + } + } + spin_unlock_bh(&pacl_node_q->lock); + + if (pacl_list->mode == 1)/* accept unless in deny list */ + res = (match) ? false : true; + else if (pacl_list->mode == 2)/* deny unless in accept list */ + res = (match) ? true : false; + else + res = true; +#endif + return res; +} diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c new file mode 100644 index 000000000000..76d2f240656e --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_wlan_util.c @@ -0,0 +1,1760 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_WLAN_UTIL_C_ + +#include +#include +#include +#include + +static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; +static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; + +static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; +static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; + +static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; +static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; +static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; +static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; +static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; +static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c}; + +unsigned char REALTEK_96B_IE23A[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; + +#define R2T_PHY_DELAY (0) + +/* define WAIT_FOR_BCN_TO_MIN (3000) */ +#define WAIT_FOR_BCN_TO_MIN (6000) +#define WAIT_FOR_BCN_TO_MAX (20000) + +static u8 rtw_basic_rate_cck[4] = { + IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, + IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK +}; + +static u8 rtw_basic_rate_ofdm[3] = { + IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK +}; + +static u8 rtw_basic_rate_mix[7] = { + IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, + IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK +}; + +int cckrates_included23a(unsigned char *rate, int ratelen) +{ + int i; + + for (i = 0; i < ratelen; i++) { + if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || + (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) + return true; + } + + return false; +} + +int cckratesonly_included23a(unsigned char *rate, int ratelen) +{ + int i; + + for (i = 0; i < ratelen; i++) { + if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && + (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) + return false; + } + + return true; +} + +unsigned char networktype_to_raid23a(unsigned char network_type) +{ + unsigned char raid; + + switch (network_type) { + case WIRELESS_11B: + raid = RATR_INX_WIRELESS_B; + break; + case WIRELESS_11A: + case WIRELESS_11G: + raid = RATR_INX_WIRELESS_G; + break; + case WIRELESS_11BG: + raid = RATR_INX_WIRELESS_GB; + break; + case WIRELESS_11_24N: + case WIRELESS_11_5N: + raid = RATR_INX_WIRELESS_N; + break; + case WIRELESS_11A_5N: + case WIRELESS_11G_24N: + raid = RATR_INX_WIRELESS_NG; + break; + case WIRELESS_11BG_24N: + raid = RATR_INX_WIRELESS_NGB; + break; + default: + raid = RATR_INX_WIRELESS_GB; + break; + } + return raid; +} + +u8 judge_network_type23a(struct rtw_adapter *padapter, unsigned char *rate, int ratelen) +{ + u8 network_type = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pmlmeext->cur_channel > 14) { + if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_5N; + network_type |= WIRELESS_11A; + } else { + if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_24N; + + if ((cckratesonly_included23a(rate, ratelen)) == true) + network_type |= WIRELESS_11B; + else if ((cckrates_included23a(rate, ratelen)) == true) + network_type |= WIRELESS_11BG; + else + network_type |= WIRELESS_11G; + } + return network_type; +} + +unsigned char ratetbl_val_2wifirate(unsigned char rate) +{ + unsigned char val = 0; + + switch (rate & 0x7f) { + case 0: + val = IEEE80211_CCK_RATE_1MB; + break; + case 1: + val = IEEE80211_CCK_RATE_2MB; + break; + case 2: + val = IEEE80211_CCK_RATE_5MB; + break; + case 3: + val = IEEE80211_CCK_RATE_11MB; + break; + case 4: + val = IEEE80211_OFDM_RATE_6MB; + break; + case 5: + val = IEEE80211_OFDM_RATE_9MB; + break; + case 6: + val = IEEE80211_OFDM_RATE_12MB; + break; + case 7: + val = IEEE80211_OFDM_RATE_18MB; + break; + case 8: + val = IEEE80211_OFDM_RATE_24MB; + break; + case 9: + val = IEEE80211_OFDM_RATE_36MB; + break; + case 10: + val = IEEE80211_OFDM_RATE_48MB; + break; + case 11: + val = IEEE80211_OFDM_RATE_54MB; + break; + } + return val; +} + +int is_basicrate(struct rtw_adapter *padapter, unsigned char rate) +{ + int i; + unsigned char val; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + for (i = 0; i < NumRates; i++) { + val = pmlmeext->basicrate[i]; + + if ((val != 0xff) && (val != 0xfe)) { + if (rate == ratetbl_val_2wifirate(val)) + return true; + } + } + + return false; +} + +unsigned int ratetbl2rateset(struct rtw_adapter *padapter, unsigned char *rateset) +{ + int i; + unsigned char rate; + unsigned int len = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + for (i = 0; i < NumRates; i++) { + rate = pmlmeext->datarate[i]; + + switch (rate) { + case 0xff: + return len; + case 0xfe: + continue; + default: + rate = ratetbl_val_2wifirate(rate); + + if (is_basicrate(padapter, rate) == true) + rate |= IEEE80211_BASIC_RATE_MASK; + + rateset[len] = rate; + len++; + break; + } + } + return len; +} + +void get_rate_set23a(struct rtw_adapter *padapter, unsigned char *pbssrate, int *bssrate_len) +{ + unsigned char supportedrates[NumRates]; + + memset(supportedrates, 0, NumRates); + *bssrate_len = ratetbl2rateset(padapter, supportedrates); + memcpy(pbssrate, supportedrates, *bssrate_len); +} + +void UpdateBrateTbl23a(struct rtw_adapter *Adapter, u8 *mBratesOS) +{ + u8 i; + u8 rate; + + /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + rate = mBratesOS[i] & 0x7f; + switch (rate) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_24MB: + mBratesOS[i] |= IEEE80211_BASIC_RATE_MASK; + break; + default: + break; + } + } +} + +void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen) +{ + u8 i; + u8 rate; + + for (i = 0; i < bssratelen; i++) { + rate = bssrateset[i] & 0x7f; + switch (rate) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + bssrateset[i] |= IEEE80211_BASIC_RATE_MASK; + break; + } + } +} + +void Save_DM_Func_Flag23a(struct rtw_adapter *padapter) +{ + u8 bSaveFlag = true; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); +} + +void Restore_DM_Func_Flag23a(struct rtw_adapter *padapter) +{ + u8 bSaveFlag = false; + rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); +} + +void Switch_DM_Func23a(struct rtw_adapter *padapter, unsigned long mode, u8 enable) +{ + if (enable == true) + rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode)); + else + rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode)); +} + +static void Set_NETYPE0_MSR(struct rtw_adapter *padapter, u8 type) +{ + rtw_hal_set_hwreg23a(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type)); +} + +void Set_MSR23a(struct rtw_adapter *padapter, u8 type) +{ + Set_NETYPE0_MSR(padapter, type); +} + +inline u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_channel; +} + +inline void rtw_set_oper_ch23a(struct rtw_adapter *adapter, u8 ch) +{ + adapter_to_dvobj(adapter)->oper_channel = ch; +} + +inline u8 rtw_get_oper_bw23a(struct rtw_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_bwmode; +} + +inline void rtw_set_oper_bw23a(struct rtw_adapter *adapter, u8 bw) +{ + adapter_to_dvobj(adapter)->oper_bwmode = bw; +} + +inline u8 rtw_get_oper_ch23aoffset(struct rtw_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_ch_offset; +} + +inline void rtw_set_oper_ch23aoffset23a(struct rtw_adapter *adapter, u8 offset) +{ + adapter_to_dvobj(adapter)->oper_ch_offset = offset; +} + +void SelectChannel23a(struct rtw_adapter *padapter, unsigned char channel) +{ + mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex); + + /* saved channel info */ + rtw_set_oper_ch23a(padapter, channel); + + rtw_hal_set_chan23a(padapter, channel); + + mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex); +} + +void SetBWMode23a(struct rtw_adapter *padapter, unsigned short bwmode, unsigned char channel_offset) +{ + mutex_lock(&adapter_to_dvobj(padapter)->setbw_mutex); + + /* saved bw info */ + rtw_set_oper_bw23a(padapter, bwmode); + rtw_set_oper_ch23aoffset23a(padapter, channel_offset); + + rtw_hal_set_bwmode23a(padapter, (enum ht_channel_width)bwmode, + channel_offset); + + mutex_unlock(&adapter_to_dvobj(padapter)->setbw_mutex); +} + +void set_channel_bwmode23a(struct rtw_adapter *padapter, unsigned char channel, + unsigned char channel_offset, unsigned short bwmode) +{ + u8 center_ch; + + if (padapter->bNotifyChannelChange) + DBG_8723A("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); + + if ((bwmode == HT_CHANNEL_WIDTH_20) || + (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) { + /* SelectChannel23a(padapter, channel); */ + center_ch = channel; + } else { + /* switch to the proper channel */ + if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) { + /* SelectChannel23a(padapter, channel + 2); */ + center_ch = channel + 2; + } else { + /* SelectChannel23a(padapter, channel - 2); */ + center_ch = channel - 2; + } + } + + /* set Channel */ + mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex); + + /* saved channel/bw info */ + rtw_set_oper_ch23a(padapter, channel); + rtw_set_oper_bw23a(padapter, bwmode); + rtw_set_oper_ch23aoffset23a(padapter, channel_offset); + + rtw_hal_set_chan23a(padapter, center_ch); /* set center channel */ + + mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex); + + SetBWMode23a(padapter, bwmode, channel_offset); +} + +int get_bsstype23a(unsigned short capability) +{ + if (capability & BIT(0)) + return WIFI_FW_AP_STATE; + else if (capability & BIT(1)) + return WIFI_FW_ADHOC_STATE; + return 0; +} + +inline u8 *get_my_bssid23a(struct wlan_bssid_ex *pnetwork) +{ + return pnetwork->MacAddress; +} + +u16 get_beacon_interval23a(struct wlan_bssid_ex *bss) +{ + unsigned short val; + memcpy((unsigned char *)&val, rtw_get_beacon_interval23a_from_ie(bss->IEs), 2); + + return le16_to_cpu(val); +} + +int is_client_associated_to_ap23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + + if (!padapter) + return _FAIL; + + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)) + return true; + else + return _FAIL; +} + +int is_client_associated_to_ibss23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && + ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) + return true; + else + return _FAIL; +} + +int is_IBSS_empty23a(struct rtw_adapter *padapter) +{ + unsigned int i; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { + if (pmlmeinfo->FW_sta_info[i].status == 1) + return _FAIL; + } + + return true; +} + +unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval) +{ + if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) + return WAIT_FOR_BCN_TO_MIN; + else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) + return WAIT_FOR_BCN_TO_MAX; + else + return bcn_interval << 2; +} + +void CAM_empty_entry23a(struct rtw_adapter *Adapter, u8 ucIndex) +{ + rtw_hal_set_hwreg23a(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); +} + +void invalidate_cam_all23a(struct rtw_adapter *padapter) +{ + rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL); +} + +void write_cam23a(struct rtw_adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) +{ + unsigned int i, val, addr; + int j; + u32 cam_val[2]; + + addr = entry << 3; + + for (j = 5; j >= 0; j--) { + switch (j) { + case 0: + val = (ctrl | (mac[0] << 16) | (mac[1] << 24)); + break; + case 1: + val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); + break; + default: + i = (j - 2) << 2; + val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); + break; + } + + cam_val[0] = val; + cam_val[1] = addr + (unsigned int)j; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); + + /* rtw_write32(padapter, WCAMI, val); */ + + /* cmd = CAM_POLLINIG | CAM_WRITE | (addr + j); */ + /* rtw_write32(padapter, RWCAM, cmd); */ + + /* DBG_8723A("%s => cam write: %x, %x\n", __func__, cmd, val); */ + + } +} + +void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry) +{ + unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + write_cam23a(padapter, entry, 0, null_sta, null_key); +} + +int allocate_fw_sta_entry23a(struct rtw_adapter *padapter) +{ + unsigned int mac_id; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) { + if (pmlmeinfo->FW_sta_info[mac_id].status == 0) { + pmlmeinfo->FW_sta_info[mac_id].status = 1; + pmlmeinfo->FW_sta_info[mac_id].retry = 0; + break; + } + } + + return mac_id; +} + +void flush_all_cam_entry23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL); + + memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); +} + +#if defined(CONFIG_8723AU_P2P) && defined(CONFIG_8723AU_P2P) +int WFD_info_handler(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + struct wifidirect_info *pwdinfo; + u8 wfd_ie[128] = {0x00}; + u32 wfd_ielen = 0; + + pwdinfo = &padapter->wdinfo; + if (rtw_get_wfd_ie((u8 *) pIE, pIE->Length, wfd_ie, &wfd_ielen)) { + u8 attr_content[ 10 ] = { 0x00 }; + u32 attr_contentlen = 0; + + DBG_8723A("[%s] Found WFD IE\n", __func__); + rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); + if (attr_contentlen) { + pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); + return true; + } + } else { + DBG_8723A("[%s] NO WFD IE\n", __func__); + } + return _FAIL; +} +#endif + +int WMM_param_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + /* struct registry_priv *pregpriv = &padapter->registrypriv; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pmlmepriv->qospriv.qos_option == 0) { + pmlmeinfo->WMM_enable = 0; + return _FAIL; + } + + pmlmeinfo->WMM_enable = 1; + memcpy(&pmlmeinfo->WMM_param, (pIE->data + 6), + sizeof(struct WMM_para_element)); + return true; +} + +void WMMOnAssocRsp23a(struct rtw_adapter *padapter) +{ + u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; + u8 acm_mask; + u16 TXOP; + u32 acParm, i; + u32 edca[4], inx[4]; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pmlmeinfo->WMM_enable == 0) { + padapter->mlmepriv.acm_mask = 0; + return; + } + + acm_mask = 0; + + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + + for (i = 0; i < 4; i++) { + ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; + ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; + + /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ + AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; + + ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); + ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; + TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); + + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + + switch (ACI) { + case 0x0: + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + acm_mask |= (ACM? BIT(1):0); + edca[XMIT_BE_QUEUE] = acParm; + break; + case 0x1: + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + /* acm_mask |= (ACM? BIT(0):0); */ + edca[XMIT_BK_QUEUE] = acParm; + break; + case 0x2: + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + acm_mask |= (ACM? BIT(2):0); + edca[XMIT_VI_QUEUE] = acParm; + break; + case 0x3: + rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + acm_mask |= (ACM? BIT(3):0); + edca[XMIT_VO_QUEUE] = acParm; + break; + } + + DBG_8723A("WMM(%x): %x, %x\n", ACI, ACM, acParm); + } + + if (padapter->registrypriv.acm_method == 1) + rtw_hal_set_hwreg23a(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); + else + padapter->mlmepriv.acm_mask = acm_mask; + + inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; + + if (pregpriv->wifi_spec == 1) { + u32 j, tmp, change_inx; + + /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ + for (i = 0; i < 4; i++) { + for (j = i+1; j < 4; j++) { + /* compare CW and AIFS */ + if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) { + change_inx = true; + } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) { + /* compare TXOP */ + if ((edca[j] >> 16) > (edca[i] >> 16)) + change_inx = true; + } + + if (change_inx) { + tmp = edca[i]; + edca[i] = edca[j]; + edca[j] = tmp; + + tmp = inx[i]; + inx[i] = inx[j]; + inx[j] = tmp; + + change_inx = false; + } + } + } + } + + for (i = 0; i<4; i++) { + pxmitpriv->wmm_para_seq[i] = inx[i]; + DBG_8723A("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); + } + + return; +} + +static void bwmode_update_check(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + struct HT_info_element *pHT_info; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + unsigned char new_bwmode; + unsigned char new_ch_offset; + + if (!pIE) + return; + if (!phtpriv->ht_option) + return; + if (pIE->Length > sizeof(struct HT_info_element)) + return; + + pHT_info = (struct HT_info_element *)pIE->data; + + if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) { + new_bwmode = HT_CHANNEL_WIDTH_40; + + switch (pHT_info->infos[0] & 0x3) { + case 1: + new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + case 3: + new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + default: + new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } else { + new_bwmode = HT_CHANNEL_WIDTH_20; + new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + if ((new_bwmode!= pmlmeext->cur_bwmode) || + (new_ch_offset!= pmlmeext->cur_ch_offset)) { + pmlmeinfo->bwmode_updated = true; + + pmlmeext->cur_bwmode = new_bwmode; + pmlmeext->cur_ch_offset = new_ch_offset; + + /* update HT info also */ + HT_info_handler23a(padapter, pIE); + } else { + pmlmeinfo->bwmode_updated = false; + } + + if (pmlmeinfo->bwmode_updated) { + struct sta_info *psta; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + + /* update ap's stainfo */ + psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress); + if (psta) { + struct ht_priv *phtpriv_sta = &psta->htpriv; + + if (phtpriv_sta->ht_option) { + /* bwmode */ + phtpriv_sta->bwmode = pmlmeext->cur_bwmode; + phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; + } else { + phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; + phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + } + } +} + +void HT_caps_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + unsigned int i; + u8 rf_type; + u8 max_AMPDU_len, min_MPDU_spacing; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if (pIE == NULL) return; + + if (phtpriv->ht_option == false) return; + + pmlmeinfo->HT_caps_enable = 1; + + for (i = 0; i < (pIE->Length); i++) { + if (i != 2) { + /* Commented by Albert 2010/07/12 */ + /* Got the endian issue here. */ + pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); + } else { + /* modify from fw by Thomas 2010/11/17 */ + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) + max_AMPDU_len = (pIE->data[i] & 0x3); + else + max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); + + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); + else + min_MPDU_spacing = (pIE->data[i] & 0x1c); + + pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; + } + } + + /* Commented by Albert 2010/07/12 */ + /* Have to handle the endian issue after copying. */ + /* HT_ext_caps didn't be used yet. */ + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); + pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps); + + rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + + /* update the MCS rates */ + for (i = 0; i < 16; i++) { + if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R23A[i]; + else + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R23A[i]; + } + return; +} + +void HT_info_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if (pIE == NULL) return; + + if (phtpriv->ht_option == false) return; + + if (pIE->Length > sizeof(struct HT_info_element)) + return; + + pmlmeinfo->HT_info_enable = 1; + memcpy(&pmlmeinfo->HT_info, pIE->data, pIE->Length); + return; +} + +void HTOnAssocRsp23a(struct rtw_adapter *padapter) +{ + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; + /* struct registry_priv *pregpriv = &padapter->registrypriv; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + DBG_8723A("%s\n", __func__); + + if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) { + pmlmeinfo->HT_enable = 1; + } else { + pmlmeinfo->HT_enable = 0; + /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + return; + } + + /* handle A-MPDU parameter field */ + /* + AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + AMPDU_para [4:2]:Min MPDU Start Spacing + */ + max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; + + rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); +} + +void ERP_IE_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pIE->Length>1) + return; + + pmlmeinfo->ERP_enable = 1; + memcpy(&pmlmeinfo->ERP_IE, pIE->data, pIE->Length); +} + +void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */ + case 0: /* off */ + psta->rtsen = 0; + psta->cts2self = 0; + break; + case 1: /* on */ + if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */ + psta->rtsen = 1; + psta->cts2self = 0; + } else { + psta->rtsen = 0; + psta->cts2self = 1; + } + break; + case 2: /* auto */ + default: + if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) { + if (pregpriv->vcs_type == 1) { + psta->rtsen = 1; + psta->cts2self = 0; + } else { + psta->rtsen = 0; + psta->cts2self = 1; + } + } else { + psta->rtsen = 0; + psta->cts2self = 0; + } + break; + } +} + +int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_len) +{ + unsigned int len; + unsigned char *p; + unsigned short val16; + struct wlan_network *cur_network = &Adapter->mlmepriv.cur_network; + u16 wpa_len = 0, rsn_len = 0; + u8 encryp_protocol = 0; + struct wlan_bssid_ex *bssid; + int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; + unsigned char *pbuf; + u32 wpa_ielen = 0; + u32 hidden_ssid = 0; + struct HT_info_element *pht_info = NULL; + struct ieee80211_ht_cap *pht_cap = NULL; + u32 bcn_channel; + unsigned short ht_cap_info; + unsigned char ht_info_infos_0; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; + u8 *pbssid = hdr->addr3; + + if (is_client_associated_to_ap23a(Adapter) == false) + return true; + + len = packet_len - sizeof(struct ieee80211_hdr_3addr); + + if (len > MAX_IE_SZ) { + DBG_8723A("%s IE too long for survey event\n", __func__); + return _FAIL; + } + + if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { + DBG_8723A("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, + MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); + return true; + } + + bssid = (struct wlan_bssid_ex *)kzalloc(sizeof(struct wlan_bssid_ex), + GFP_ATOMIC); + + if (ieee80211_is_beacon(hdr->frame_control)) + bssid->reserved = 1; + + bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; + + /* below is to copy the information element */ + bssid->IELength = len; + memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength); + + /* check bw and channel offset */ + /* parsing HT_CAP_IE */ + p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p && len>0) { + pht_cap = (struct ieee80211_ht_cap *)(p + 2); + ht_cap_info = pht_cap->cap_info; + } else { + ht_cap_info = 0; + } + /* parsing HT_INFO_IE */ + p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p && len>0) { + pht_info = (struct HT_info_element *)(p + 2); + ht_info_infos_0 = pht_info->infos[0]; + } else { + ht_info_infos_0 = 0; + } + if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || + ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { + DBG_8723A("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + ht_cap_info, ht_info_infos_0); + DBG_8723A("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); + DBG_8723A("%s bw mode change, disconnect\n", __func__); + /* bcn_info_update */ + cur_network->BcnInfo.ht_cap_info = ht_cap_info; + cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; + /* to do : need to check that whether modify related register of BB or not */ + } + + /* Checking for channel */ + p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p) { + bcn_channel = *(p + 2); + } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ + p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (pht_info) { + bcn_channel = pht_info->primary_channel; + } else { /* we don't find channel IE, so don't check it */ + DBG_8723A("Oops: %s we don't find channel IE, so don't check it\n", __func__); + bcn_channel = Adapter->mlmeextpriv.cur_channel; + } + } + if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { + DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", __func__, + bcn_channel, Adapter->mlmeextpriv.cur_channel); + goto _mismatch; + } + + /* checking SSID */ + if ((p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_)) == NULL) { + DBG_8723A("%s marc: cannot find SSID for survey event\n", __func__); + hidden_ssid = true; + } else { + hidden_ssid = false; + } + + if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { + memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1)); + bssid->Ssid.ssid_len = *(p + 1); + } else { + bssid->Ssid.ssid_len = 0; + bssid->Ssid.ssid[0] = '\0'; + } + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " + "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, + bssid->Ssid.ssid, bssid->Ssid.ssid_len, + cur_network->network.Ssid.ssid, + cur_network->network.Ssid.ssid_len)); + + if (memcmp(bssid->Ssid.ssid, cur_network->network.Ssid.ssid, 32) || + bssid->Ssid.ssid_len != cur_network->network.Ssid.ssid_len) { + if (bssid->Ssid.ssid[0] != '\0' && + bssid->Ssid.ssid_len != 0) { /* not hidden ssid */ + DBG_8723A("%s(), SSID is not match return FAIL\n", + __func__); + goto _mismatch; + } + } + + /* check encryption info */ + val16 = rtw_get_capability23a((struct wlan_bssid_ex *)bssid); + + if (val16 & BIT(4)) + bssid->Privacy = 1; + else + bssid->Privacy = 0; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", + __func__, cur_network->network.Privacy, bssid->Privacy)); + if (cur_network->network.Privacy != bssid->Privacy) { + DBG_8723A("%s(), privacy is not match return FAIL\n", __func__); + goto _mismatch; + } + + rtw_get_sec_ie23a(bssid->IEs, bssid->IELength, NULL,&rsn_len, NULL,&wpa_len); + + if (rsn_len > 0) { + encryp_protocol = ENCRYP_PROTOCOL_WPA2; + } else if (wpa_len > 0) { + encryp_protocol = ENCRYP_PROTOCOL_WPA; + } else { + if (bssid->Privacy) + encryp_protocol = ENCRYP_PROTOCOL_WEP; + } + + if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { + DBG_8723A("%s(): enctyp is not match , return FAIL\n", __func__); + goto _mismatch; + } + + if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { + pbuf = rtw_get_wpa_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); + if (pbuf && (wpa_ielen>0)) { + if (_SUCCESS == rtw_parse_wpa_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, + pairwise_cipher, group_cipher, is_8021x)); + } + } else { + pbuf = rtw_get_wpa2_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); + + if (pbuf && (wpa_ielen>0)) { + if (_SUCCESS == rtw_parse_wpa2_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, + ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", + __func__, pairwise_cipher, group_cipher, is_8021x)); + } + } + } + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, + ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher)); + if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { + DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__, + pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, + group_cipher, cur_network->BcnInfo.group_cipher); + goto _mismatch; + } + + if (is_8021x != cur_network->BcnInfo.is_8021x) { + DBG_8723A("%s authentication is not match , return FAIL\n", __func__); + goto _mismatch; + } + } + + kfree(bssid); + return _SUCCESS; + +_mismatch: + kfree(bssid); + + return _FAIL; +} + +void update_beacon23a_info(struct rtw_adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) +{ + unsigned int i; + unsigned int len; + struct ndis_802_11_var_ies * pIE; + + len = pkt_len - + (_BEACON_IE_OFFSET_ + sizeof(struct ieee80211_hdr_3addr)); + + for (i = 0; i < len;) { + pIE = (struct ndis_802_11_var_ies *)(pframe + (_BEACON_IE_OFFSET_ + sizeof(struct ieee80211_hdr_3addr)) + i); + + switch (pIE->ElementID) { + case _HT_EXTRA_INFO_IE_: /* HT info */ + /* HT_info_handler23a(padapter, pIE); */ + bwmode_update_check(padapter, pIE); + break; + case _ERPINFO_IE_: + ERP_IE_handler23a(padapter, pIE); + VCS_update23a(padapter, psta); + break; + default: + break; + } + i += (pIE->Length + 2); + } +} + +unsigned int is_ap_in_tkip23a(struct rtw_adapter *padapter) +{ + u32 i; + struct ndis_802_11_var_ies * pIE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + + if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) { + pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if ((!memcmp(pIE->data, RTW_WPA_OUI23A, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER23A, 4))) + return true; + break; + case _RSN_IE_2_: + if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER23A, 4)) + return true; + break; + default: + break; + } + i += (pIE->Length + 2); + } + return false; + } else { + return false; + } +} + +unsigned int should_forbid_n_rate23a(struct rtw_adapter * padapter) +{ + u32 i; + struct ndis_802_11_var_ies * pIE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; + + if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(struct ndis_802_11_fixed_ies); i < cur_network->IELength;) { + pIE = (struct ndis_802_11_var_ies *)(cur_network->IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) && + ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP23A, 4)) || + (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP23A, 4)))) + return false; + break; + case _RSN_IE_2_: + if ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP23A, 4)) || + (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP23A, 4))) + return false; + default: + break; + } + + i += (pIE->Length + 2); + } + return true; + } else { + return false; + } +} + +unsigned int is_ap_in_wep23a(struct rtw_adapter *padapter) +{ + u32 i; + struct ndis_802_11_var_ies * pIE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + + if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) { + pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4)) + return false; + break; + case _RSN_IE_2_: + return false; + + default: + break; + } + + i += (pIE->Length + 2); + } + + return true; + } else { + return false; + } +} + +int wifirate2_ratetbl_inx23a(unsigned char rate) +{ + int inx = 0; + rate = rate & 0x7f; + + switch (rate) { + case 54*2: + inx = 11; + break; + case 48*2: + inx = 10; + break; + case 36*2: + inx = 9; + break; + case 24*2: + inx = 8; + break; + case 18*2: + inx = 7; + break; + case 12*2: + inx = 6; + break; + case 9*2: + inx = 5; + break; + case 6*2: + inx = 4; + break; + case 11*2: + inx = 3; + break; + case 11: + inx = 2; + break; + case 2*2: + inx = 1; + break; + case 1*2: + inx = 0; + break; + } + return inx; +} + +unsigned int update_basic_rate23a(unsigned char *ptn, unsigned int ptn_sz) +{ + unsigned int i, num_of_rate; + unsigned int mask = 0; + + num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; + + for (i = 0; i < num_of_rate; i++) { + if ((*(ptn + i)) & 0x80) + mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); + } + return mask; +} + +unsigned int update_supported_rate23a(unsigned char *ptn, unsigned int ptn_sz) +{ + unsigned int i, num_of_rate; + unsigned int mask = 0; + + num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz; + + for (i = 0; i < num_of_rate; i++) + mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i)); + return mask; +} + +unsigned int update_MSC_rate23a(struct HT_caps_element *pHT_caps) +{ + unsigned int mask = 0; + + mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20)); + + return mask; +} + +int support_short_GI23a(struct rtw_adapter *padapter, + struct HT_caps_element *pHT_caps) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + unsigned char bit_offset; + + if (!(pmlmeinfo->HT_enable)) + return _FAIL; + if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK)) + return _FAIL; + bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40)? 6: 5; + + if (pHT_caps->u.HT_cap_element.HT_caps_info & (0x1 << bit_offset)) + return _SUCCESS; + else + return _FAIL; +} + +unsigned char get_highest_rate_idx23a(u32 mask) +{ + int i; + unsigned char rate_idx = 0; + + for (i = 27; i >= 0; i--) { + if (mask & BIT(i)) { + rate_idx = i; + break; + } + } + return rate_idx; +} + +unsigned char get_highest_mcs_rate(struct HT_caps_element *pHT_caps) +{ + int i, mcs_rate; + + mcs_rate = (pHT_caps->u.HT_cap_element.MCS_rate[0] | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 8)); + + for (i = 15; i >= 0; i--) { + if (mcs_rate & (0x1 << i)) + break; + } + return i; +} + +void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + rtw_hal_update_ra_mask23a(psta, 0); +} + +void enable_rate_adaptive(struct rtw_adapter *padapter, struct sta_info *psta) +{ + Update_RA_Entry23a(padapter, psta); +} + +void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + /* rate adaptive */ + enable_rate_adaptive(padapter, psta); +} + +/* Update RRSR and Rate for USERATE */ +void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode) +{ + unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info* pwdinfo = &padapter->wdinfo; + + /* Added by Albert 2011/03/22 */ + /* In the P2P mode, the driver should not support the b mode. */ + /* So, the Tx packet shouldn't use the CCK rate */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; +#endif /* CONFIG_8723AU_P2P */ + + memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); + + if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) { + memcpy(supported_rates, rtw_basic_rate_cck, 4); + } else if (wirelessmode & WIRELESS_11B) { + memcpy(supported_rates, rtw_basic_rate_mix, 7); + } else { + memcpy(supported_rates, rtw_basic_rate_ofdm, 3); + } + + if (wirelessmode & WIRELESS_11B) + update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); + else + update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, supported_rates); +} + +unsigned char check_assoc_AP23a(u8 *pframe, uint len) +{ + unsigned int i; + struct ndis_802_11_var_ies * pIE; + u8 epigram_vendor_flag; + u8 ralink_vendor_flag; + epigram_vendor_flag = 0; + ralink_vendor_flag = 0; + + for (i = sizeof(struct ndis_802_11_fixed_ies); i < len;) { + pIE = (struct ndis_802_11_var_ies *)(pframe + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || + (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { + DBG_8723A("link to Artheros AP\n"); + return HT_IOT_PEER_ATHEROS; + } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) || + !memcmp(pIE->data, BROADCOM_OUI2, 3) || + !memcmp(pIE->data, BROADCOM_OUI2, 3)) { + DBG_8723A("link to Broadcom AP\n"); + return HT_IOT_PEER_BROADCOM; + } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) { + DBG_8723A("link to Marvell AP\n"); + return HT_IOT_PEER_MARVELL; + } else if (!memcmp(pIE->data, RALINK_OUI, 3)) { + if (!ralink_vendor_flag) { + ralink_vendor_flag = 1; + } else { + DBG_8723A("link to Ralink AP\n"); + return HT_IOT_PEER_RALINK; + } + } else if (!memcmp(pIE->data, CISCO_OUI, 3)) { + DBG_8723A("link to Cisco AP\n"); + return HT_IOT_PEER_CISCO; + } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) { + DBG_8723A("link to Realtek 96B\n"); + return HT_IOT_PEER_REALTEK; + } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) { + DBG_8723A("link to Airgo Cap\n"); + return HT_IOT_PEER_AIRGO; + } else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) { + epigram_vendor_flag = 1; + if (ralink_vendor_flag) { + DBG_8723A("link to Tenda W311R AP\n"); + return HT_IOT_PEER_TENDA; + } else { + DBG_8723A("Capture EPIGRAM_OUI\n"); + } + } else { + break; + } + default: + break; + } + + i += (pIE->Length + 2); + } + + if (ralink_vendor_flag && !epigram_vendor_flag) { + DBG_8723A("link to Ralink AP\n"); + return HT_IOT_PEER_RALINK; + } else if (ralink_vendor_flag && epigram_vendor_flag) { + DBG_8723A("link to Tenda W311R AP\n"); + return HT_IOT_PEER_TENDA; + } else { + DBG_8723A("link to new AP\n"); + return HT_IOT_PEER_UNKNOWN; + } +} + +void update_IOT_info23a(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + switch (pmlmeinfo->assoc_AP_vendor) { + case HT_IOT_PEER_MARVELL: + pmlmeinfo->turboMode_cts2self = 1; + pmlmeinfo->turboMode_rtsen = 0; + break; + case HT_IOT_PEER_RALINK: + pmlmeinfo->turboMode_cts2self = 0; + pmlmeinfo->turboMode_rtsen = 1; + /* disable high power */ + Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR, + false); + break; + case HT_IOT_PEER_REALTEK: + /* rtw_write16(padapter, 0x4cc, 0xffff); */ + /* rtw_write16(padapter, 0x546, 0x01c0); */ + /* disable high power */ + Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR, + false); + break; + default: + pmlmeinfo->turboMode_cts2self = 0; + pmlmeinfo->turboMode_rtsen = 1; + break; + } +} + +void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap) +{ + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + bool ShortPreamble; + + if (updateCap & cShortPreamble) { + /* Short Preamble */ + if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { + /* PREAMBLE_LONG or PREAMBLE_AUTO */ + ShortPreamble = true; + pmlmeinfo->preamble_mode = PREAMBLE_SHORT; + rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + } + } else { /* Long Preamble */ + if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { + /* PREAMBLE_SHORT or PREAMBLE_AUTO */ + ShortPreamble = false; + pmlmeinfo->preamble_mode = PREAMBLE_LONG; + rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + } + } + if (updateCap & cIBSS) { + /* Filen: See 802.11-2007 p.91 */ + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } else { + /* Filen: See 802.11-2007 p.90 */ + if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) { + if (updateCap & cShortSlotTime) { /* Short Slot Time */ + if (pmlmeinfo->slotTime != SHORT_SLOT_TIME) + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + } else { /* Long Slot Time */ + if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } + } else if (pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) { + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + } else { + /* B Mode */ + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } + } + rtw_hal_set_hwreg23a(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); +} + +void update_wireless_mode23a(struct rtw_adapter *padapter) +{ + int ratelen, network_type = 0; + u32 SIFS_Timer; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + unsigned char *rate = cur_network->SupportedRates; + + ratelen = rtw_get_rateset_len23a(cur_network->SupportedRates); + + if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) + pmlmeinfo->HT_enable = 1; + + if (pmlmeext->cur_channel > 14) { + if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_5N; + network_type |= WIRELESS_11A; + } else { + if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_24N; + + if ((cckratesonly_included23a(rate, ratelen)) == true) + network_type |= WIRELESS_11B; + else if ((cckrates_included23a(rate, ratelen)) == true) + network_type |= WIRELESS_11BG; + else + network_type |= WIRELESS_11G; + } + + pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; + + SIFS_Timer = 0x0a0a0808; /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ + /* change this value if having IOT issues. */ + + padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); + + if (pmlmeext->cur_wireless_mode & WIRELESS_11B) + update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB); + else + update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB); +} + +void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { + /* Only B, B/G, and B/G/N AP could use CCK rate */ + memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4); + } else { + memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 4); + } +} + +int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx) +{ + unsigned int ie_len; + struct ndis_802_11_var_ies *pIE; + int supportRateNum = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); + if (pIE == NULL) + return _FAIL; + + memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); + supportRateNum = ie_len; + + pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); + if (pIE) + memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); + return _SUCCESS; +} + +void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr) +{ + struct sta_info *psta; + u16 tid, start_seq, param; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_priv *pstapriv = &padapter->stapriv; + struct ADDBA_request *preq = (struct ADDBA_request*)paddba_req; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + psta = rtw_get_stainfo23a(pstapriv, addr); + + if (psta) { + start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; + + param = le16_to_cpu(preq->BA_para_set); + tid = (param>>2)&0x0f; + + preorder_ctrl = &psta->recvreorder_ctrl[tid]; + + preorder_ctrl->indicate_seq = 0xffff; + + preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq == true)? true :false; + } +} + +void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) +{ + u8 *pIE; + u32 *pbuf; + + pIE = pframe + sizeof(struct ieee80211_hdr_3addr); + pbuf = (u32 *)pIE; + + pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); + + pmlmeext->TSFValue = pmlmeext->TSFValue << 32; + + pmlmeext->TSFValue |= le32_to_cpu(*pbuf); +} + +void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext) +{ + rtw_hal_set_hwreg23a(padapter, HW_VAR_CORRECT_TSF, NULL); +} + +void beacon_timing_control23a(struct rtw_adapter *padapter) +{ + rtw_hal_bcn_related_reg_setting23a(padapter); +} + +static struct rtw_adapter *pbuddy_padapter; + +int rtw_handle_dualmac23a(struct rtw_adapter *adapter, bool init) +{ + int status = _SUCCESS; + + if (init) { + if (pbuddy_padapter == NULL) { + pbuddy_padapter = adapter; + DBG_8723A("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__); + } else { + adapter->pbuddy_adapter = pbuddy_padapter; + pbuddy_padapter->pbuddy_adapter = adapter; + /* clear global value */ + pbuddy_padapter = NULL; + DBG_8723A("%s(): pbuddy_padapter exist, Exchange Information\n", __func__); + } + } else { + pbuddy_padapter = NULL; + } + return status; +} diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c new file mode 100644 index 000000000000..a1abba053944 --- /dev/null +++ b/drivers/staging/rtl8723au/core/rtw_xmit.c @@ -0,0 +1,2463 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTW_XMIT_C_ + +#include +#include +#include +#include +#include +#include + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static void _init_txservq(struct tx_servq *ptxservq) +{ + + INIT_LIST_HEAD(&ptxservq->tx_pending); + _rtw_init_queue23a(&ptxservq->sta_pending); + ptxservq->qcnt = 0; + +} + +void _rtw_init_sta_xmit_priv23a(struct sta_xmit_priv *psta_xmitpriv) +{ + + spin_lock_init(&psta_xmitpriv->lock); + + /* for (i = 0 ; i < MAX_NUMBLKS; i++) */ + /* _init_txservq(&psta_xmitpriv->blk_q[i]); */ + + _init_txservq(&psta_xmitpriv->be_q); + _init_txservq(&psta_xmitpriv->bk_q); + _init_txservq(&psta_xmitpriv->vi_q); + _init_txservq(&psta_xmitpriv->vo_q); + INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); + INIT_LIST_HEAD(&psta_xmitpriv->apsd); + +} + +s32 _rtw_init_xmit_priv23a(struct xmit_priv *pxmitpriv, struct rtw_adapter *padapter) +{ + int i; + struct xmit_buf *pxmitbuf; + struct xmit_frame *pxframe; + int res = _SUCCESS; + u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; + u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; + + /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ + /* memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); */ + + spin_lock_init(&pxmitpriv->lock); + spin_lock_init(&pxmitpriv->lock_sctx); + sema_init(&pxmitpriv->xmit_sema, 0); + sema_init(&pxmitpriv->terminate_xmitthread_sema, 0); + + /* + Please insert all the queue initializaiton using _rtw_init_queue23a below + */ + + pxmitpriv->adapter = padapter; + + _rtw_init_queue23a(&pxmitpriv->be_pending); + _rtw_init_queue23a(&pxmitpriv->bk_pending); + _rtw_init_queue23a(&pxmitpriv->vi_pending); + _rtw_init_queue23a(&pxmitpriv->vo_pending); + _rtw_init_queue23a(&pxmitpriv->bm_pending); + + _rtw_init_queue23a(&pxmitpriv->free_xmit_queue); + + /* + Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, + and initialize free_xmit_frame below. + Please also apply free_txobj to link_up all the xmit_frames... + */ + + pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); + + if (pxmitpriv->pallocated_frame_buf == NULL) { + pxmitpriv->pxmit_frame_buf = NULL; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n")); + res = _FAIL; + goto exit; + } + pxmitpriv->pxmit_frame_buf = PTR_ALIGN(pxmitpriv->pallocated_frame_buf, 4); + + pxframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; + + for (i = 0; i < NR_XMITFRAME; i++) { + INIT_LIST_HEAD(&pxframe->list); + + pxframe->padapter = padapter; + pxframe->frame_tag = NULL_FRAMETAG; + + pxframe->pkt = NULL; + + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + list_add_tail(&pxframe->list, + &pxmitpriv->free_xmit_queue.queue); + + pxframe++; + } + + pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; + + pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; + + /* init xmit_buf */ + _rtw_init_queue23a(&pxmitpriv->free_xmitbuf_queue); + INIT_LIST_HEAD(&pxmitpriv->xmitbuf_list); + _rtw_init_queue23a(&pxmitpriv->pending_xmitbuf_queue); + + for (i = 0; i < NR_XMITBUFF; i++) { + pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL); + if (!pxmitbuf) + goto fail; + INIT_LIST_HEAD(&pxmitbuf->list); + INIT_LIST_HEAD(&pxmitbuf->list2); + + pxmitbuf->padapter = padapter; + + /* Tx buf allocation may fail sometimes, so sleep and retry. */ + res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf, + (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); + if (res == _FAIL) { + goto fail; + } + + list_add_tail(&pxmitbuf->list, + &pxmitpriv->free_xmitbuf_queue.queue); + list_add_tail(&pxmitbuf->list2, + &pxmitpriv->xmitbuf_list); + } + + pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; + + /* init xframe_ext queue, the same count as extbuf */ + _rtw_init_queue23a(&pxmitpriv->free_xframe_ext_queue); + + pxmitpriv->xframe_ext_alloc_addr = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_frame) + 4); + + if (pxmitpriv->xframe_ext_alloc_addr == NULL) { + pxmitpriv->xframe_ext = NULL; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n")); + res = _FAIL; + goto exit; + } + pxmitpriv->xframe_ext = PTR_ALIGN(pxmitpriv->xframe_ext_alloc_addr, 4); + pxframe = (struct xmit_frame*)pxmitpriv->xframe_ext; + + for (i = 0; i < num_xmit_extbuf; i++) { + INIT_LIST_HEAD(&pxframe->list); + + pxframe->padapter = padapter; + pxframe->frame_tag = NULL_FRAMETAG; + + pxframe->pkt = NULL; + + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + pxframe->ext_tag = 1; + + list_add_tail(&pxframe->list, + &pxmitpriv->free_xframe_ext_queue.queue); + + pxframe++; + } + pxmitpriv->free_xframe_ext_cnt = num_xmit_extbuf; + + /* Init xmit extension buff */ + _rtw_init_queue23a(&pxmitpriv->free_xmit_extbuf_queue); + INIT_LIST_HEAD(&pxmitpriv->xmitextbuf_list); + + for (i = 0; i < num_xmit_extbuf; i++) { + pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL); + if (!pxmitbuf) + goto fail; + INIT_LIST_HEAD(&pxmitbuf->list); + INIT_LIST_HEAD(&pxmitbuf->list2); + + pxmitbuf->padapter = padapter; + + /* Tx buf allocation may fail sometimes, so sleep and retry. */ + res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf, + max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); + if (res == _FAIL) { + goto exit; + } + + list_add_tail(&pxmitbuf->list, + &pxmitpriv->free_xmit_extbuf_queue.queue); + list_add_tail(&pxmitbuf->list2, + &pxmitpriv->xmitextbuf_list); + } + + pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; + + rtw_alloc_hwxmits23a(padapter); + rtw_init_hwxmits23a(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); + + for (i = 0; i < 4; i ++) + pxmitpriv->wmm_para_seq[i] = i; + + pxmitpriv->txirp_cnt = 1; + + sema_init(&pxmitpriv->tx_retevt, 0); + + /* per AC pending irp */ + pxmitpriv->beq_cnt = 0; + pxmitpriv->bkq_cnt = 0; + pxmitpriv->viq_cnt = 0; + pxmitpriv->voq_cnt = 0; + + pxmitpriv->ack_tx = false; + mutex_init(&pxmitpriv->ack_tx_mutex); + rtw_sctx_init23a(&pxmitpriv->ack_tx_ops, 0); + rtw_hal_init23a_xmit_priv(padapter); + +exit: + + return res; +fail: + goto exit; +} + +void _rtw_free_xmit_priv23a (struct xmit_priv *pxmitpriv) +{ + struct rtw_adapter *padapter = pxmitpriv->adapter; + struct xmit_frame *pxmitframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf; + struct xmit_buf *pxmitbuf; + struct list_head *plist, *ptmp; + u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; + int i; + + rtw_hal_free_xmit_priv23a(padapter); + + if (pxmitpriv->pxmit_frame_buf == NULL) + return; + for (i = 0; i < NR_XMITFRAME; i++) { + rtw_os_xmit_complete23a(padapter, pxmitframe); + pxmitframe++; + } + + list_for_each_safe(plist, ptmp, &pxmitpriv->xmitbuf_list) { + pxmitbuf = container_of(plist, struct xmit_buf, list2); + list_del_init(&pxmitbuf->list2); + rtw_os_xmit_resource_free23a(padapter, pxmitbuf); + kfree(pxmitbuf); + } + + if (pxmitpriv->pallocated_frame_buf) { + rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4); + } + + /* free xframe_ext queue, the same count as extbuf */ + if ((pxmitframe = (struct xmit_frame*)pxmitpriv->xframe_ext)) { + for (i = 0; ixframe_ext_alloc_addr) + rtw_vmfree(pxmitpriv->xframe_ext_alloc_addr, num_xmit_extbuf * sizeof(struct xmit_frame) + 4); + + /* free xmit extension buff */ + list_for_each_safe(plist, ptmp, &pxmitpriv->xmitextbuf_list) { + pxmitbuf = container_of(plist, struct xmit_buf, list2); + list_del_init(&pxmitbuf->list2); + rtw_os_xmit_resource_free23a(padapter, pxmitbuf); + kfree(pxmitbuf); + } + + rtw_free_hwxmits23a(padapter); + mutex_destroy(&pxmitpriv->ack_tx_mutex); +} + +static void update_attrib_vcs_info(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + u32 sz; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *psta = pattrib->psta; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]); + } + + if (psta == NULL) { + DBG_8723A("%s, psta == NUL\n", __func__); + return; + } + + if (!(psta->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return; + } + + if (pattrib->nr_frags != 1) + sz = padapter->xmitpriv.frag_len; + else /* no frag */ + sz = pattrib->last_txcmdsz; + + /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ + /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ + /* Other fragments are protected by previous fragment. */ + /* So we only need to check the length of first fragment. */ + if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { + if (sz > padapter->registrypriv.rts_thresh) { + pattrib->vcs_mode = RTS_CTS; + } else { + if (psta->rtsen) + pattrib->vcs_mode = RTS_CTS; + else if (psta->cts2self) + pattrib->vcs_mode = CTS_TO_SELF; + else + pattrib->vcs_mode = NONE_VCS; + } + } else { + while (true) { + /* IOT action */ + if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && + (pattrib->ampdu_en) && + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + pattrib->vcs_mode = CTS_TO_SELF; + break; + } + + /* check ERP protection */ + if (psta->rtsen || psta->cts2self) { + if (psta->rtsen) + pattrib->vcs_mode = RTS_CTS; + else if (psta->cts2self) + pattrib->vcs_mode = CTS_TO_SELF; + + break; + } + + /* check HT op mode */ + if (pattrib->ht_en) { + u8 HTOpMode = pmlmeinfo->HT_protection; + if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || + (!pmlmeext->cur_bwmode && HTOpMode == 3)) { + pattrib->vcs_mode = RTS_CTS; + break; + } + } + + /* check rts */ + if (sz > padapter->registrypriv.rts_thresh) { + pattrib->vcs_mode = RTS_CTS; + break; + } + + /* to do list: check MIMO power save condition. */ + + /* check AMPDU aggregation for TXOP */ + if (pattrib->ampdu_en) { + pattrib->vcs_mode = RTS_CTS; + break; + } + + pattrib->vcs_mode = NONE_VCS; + break; + } + } +} + +static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta) +{ + /*if (psta->rtsen) + pattrib->vcs_mode = RTS_CTS; + else if (psta->cts2self) + pattrib->vcs_mode = CTS_TO_SELF; + else + pattrib->vcs_mode = NONE_VCS;*/ + + pattrib->mdata = 0; + pattrib->eosp = 0; + pattrib->triggered = 0; + + /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ + pattrib->qos_en = psta->qos_option; + + pattrib->raid = psta->raid; + pattrib->ht_en = psta->htpriv.ht_option; + pattrib->bwmode = psta->htpriv.bwmode; + pattrib->ch_offset = psta->htpriv.ch_offset; + pattrib->sgi = psta->htpriv.sgi; + pattrib->ampdu_en = false; + + pattrib->retry_ctrl = false; +} + +u8 qos_acm23a(u8 acm_mask, u8 priority) +{ + u8 change_priority = priority; + + switch (priority) { + case 0: + case 3: + if (acm_mask & BIT(1)) + change_priority = 1; + break; + case 1: + case 2: + break; + case 4: + case 5: + if (acm_mask & BIT(2)) + change_priority = 0; + break; + case 6: + case 7: + if (acm_mask & BIT(3)) + change_priority = 5; + break; + default: + DBG_8723A("qos_acm23a(): invalid pattrib->priority: %d!!!\n", + priority); + break; + } + + return change_priority; +} + +static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) +{ + struct ethhdr etherhdr; + struct iphdr ip_hdr; + s32 UserPriority = 0; + + _rtw_open_pktfile23a(ppktfile->pkt, ppktfile); + _rtw_pktfile_read23a(ppktfile, (unsigned char*)ðerhdr, ETH_HLEN); + + /* get UserPriority from IP hdr */ + if (pattrib->ether_type == 0x0800) { + _rtw_pktfile_read23a(ppktfile, (u8*)&ip_hdr, sizeof(ip_hdr)); +/* UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ + UserPriority = ip_hdr.tos >> 5; + } else if (pattrib->ether_type == 0x888e) { + /* "When priority processing of data frames is supported, */ + /* a STA's SME should send EAPOL-Key frames at the highest + priority." */ + UserPriority = 7; + } + + pattrib->priority = UserPriority; + pattrib->hdrlen = sizeof(struct ieee80211_qos_hdr); + pattrib->subtype = WIFI_QOS_DATA_TYPE; +} + +static s32 update_attrib(struct rtw_adapter *padapter, + struct sk_buff *pkt, struct pkt_attrib *pattrib) +{ + uint i; + struct pkt_file pktfile; + struct sta_info *psta = NULL; + struct ethhdr etherhdr; + + int bmcast; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + int res = _SUCCESS; + + _rtw_open_pktfile23a(pkt, &pktfile); + i = _rtw_pktfile_read23a(&pktfile, (u8*)ðerhdr, ETH_HLEN); + + pattrib->ether_type = ntohs(etherhdr.h_proto); + + memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); + memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); + + pattrib->pctrl = 0; + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + } + else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + } + else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); + } + + pattrib->pktlen = pktfile.pkt_len; + + if (pattrib->ether_type == ETH_P_IP) { + /* The following is for DHCP and ARP packet, we use cck1M + to tx these packets and let LPS awake some time */ + /* to prevent DHCP protocol fail */ + u8 tmp[24]; + _rtw_pktfile_read23a(&pktfile, &tmp[0], 24); + pattrib->dhcp_pkt = 0; + if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ + if (ETH_P_IP == pattrib->ether_type) {/* IP header */ + if (((tmp[21] == 68) && (tmp[23] == 67)) || + ((tmp[21] == 67) && (tmp[23] == 68))) { + /* 68 : UDP BOOTP client */ + /* 67 : UDP BOOTP server */ + RT_TRACE(_module_rtl871x_xmit_c_, + _drv_err_, + ("======================" + "update_attrib: get DHCP " + "Packet\n")); + pattrib->dhcp_pkt = 1; + } + } + } + } else if (0x888e == pattrib->ether_type) { + DBG_8723A_LEVEL(_drv_always_, "send eapol packet\n"); + } + + if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) { + rtw_set_scan_deny(padapter, 3000); + } + + /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ + if ((pattrib->ether_type == 0x0806) || + (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) { + rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SPECIAL_PACKET, 1); + } + + bmcast = is_multicast_ether_addr(pattrib->ra); + + /* get sta_info */ + if (bmcast) { + psta = rtw_get_bcmc_stainfo23a(padapter); + } else { + psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); + if (psta == NULL) { /* if we cannot get psta => drrp the pkt */ + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, + ("\nupdate_attrib => get sta_info fail, ra:" + MAC_FMT"\n", MAC_ARG(pattrib->ra))); + res = _FAIL; + goto exit; + } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && + (!(psta->state & _FW_LINKED))) { + res = _FAIL; + goto exit; + } + } + + if (psta) { + pattrib->mac_id = psta->mac_id; + /* DBG_8723A("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */ + pattrib->psta = psta; + } else { + /* if we cannot get psta => drop the pkt */ + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, + ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT + "\n", MAC_ARG(pattrib->ra))); + res = _FAIL; + goto exit; + } + + pattrib->ack_policy = 0; + /* get ether_hdr_len */ + + /* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */ + pattrib->pkt_hdrlen = ETH_HLEN; + + pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr); + pattrib->subtype = WIFI_DATA_TYPE; + pattrib->priority = 0; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE | + WIFI_ADHOC_MASTER_STATE)) { + if (psta->qos_option) + set_qos(&pktfile, pattrib); + } else { + if (pqospriv->qos_option) { + set_qos(&pktfile, pattrib); + + if (pmlmepriv->acm_mask != 0) { + pattrib->priority = qos_acm23a(pmlmepriv->acm_mask, + pattrib->priority); + } + } + } + + if (psta->ieee8021x_blocked == true) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("\n psta->ieee8021x_blocked == true\n")); + + pattrib->encrypt = 0; + + if ((pattrib->ether_type != 0x888e) && + (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("\npsta->ieee8021x_blocked == true, " + "pattrib->ether_type(%.4x) != 0x888e\n", + pattrib->ether_type)); + res = _FAIL; + goto exit; + } + } else { + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); + + switch (psecuritypriv->dot11AuthAlgrthm) { + case dot11AuthAlgrthm_Open: + case dot11AuthAlgrthm_Shared: + case dot11AuthAlgrthm_Auto: + pattrib->key_idx = + (u8)psecuritypriv->dot11PrivacyKeyIndex; + break; + case dot11AuthAlgrthm_8021X: + if (bmcast) + pattrib->key_idx = + (u8)psecuritypriv->dot118021XGrpKeyid; + else + pattrib->key_idx = 0; + break; + default: + pattrib->key_idx = 0; + break; + } + + } + + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + pattrib->iv_len = 4; + pattrib->icv_len = 4; + break; + + case _TKIP_: + pattrib->iv_len = 8; + pattrib->icv_len = 4; + + if (padapter->securitypriv.busetkipkey == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("\npadapter->securitypriv.busetkip" + "key(%d) == _FAIL drop packet\n", + padapter->securitypriv.busetkipkey)); + res = _FAIL; + goto exit; + } + + break; + case _AES_: + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("pattrib->encrypt =%d (_AES_)\n", pattrib->encrypt)); + pattrib->iv_len = 8; + pattrib->icv_len = 8; + break; + + default: + pattrib->iv_len = 0; + pattrib->icv_len = 0; + break; + } + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("update_attrib: encrypt =%d\n", pattrib->encrypt)); + + if (pattrib->encrypt && psecuritypriv->hw_decrypted == false) { + pattrib->bswenc = true; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("update_attrib: encrypt =%d bswenc = true\n", + pattrib->encrypt)); + } else { + pattrib->bswenc = false; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("update_attrib: bswenc = false\n")); + } + update_attrib_phy_info(pattrib, psta); + +exit: + + return res; +} + +static s32 xmitframe_addmic(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) { + struct mic_data micdata; + struct sta_info *stainfo; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + int curfragnum, length; + u8 *pframe, *payload, mic[8]; + u8 priority[4]= {0x0, 0x0, 0x0, 0x0}; + u8 hw_hdr_offset = 0; + int bmcst = is_multicast_ether_addr(pattrib->ra); + + if (pattrib->psta) { + stainfo = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + stainfo = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]); + } + + if (!stainfo) { + DBG_8723A("%s, psta == NUL\n", __func__); + return _FAIL; + } + + if (!(stainfo->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", + __func__, stainfo->state); + return _FAIL; + } + + hw_hdr_offset = TXDESC_OFFSET; + + if (pattrib->encrypt == _TKIP_) { + /* encode mic code */ + if (stainfo) { + u8 null_key[16]={0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0}; + + pframe = pxmitframe->buf_addr + hw_hdr_offset; + + if (bmcst) { + if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) { + return _FAIL; + } + /* start to calculate the mic code */ + rtw_secmicsetkey23a(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); + } else { + if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], + null_key, 16)) { + return _FAIL; + } + /* start to calculate the mic code */ + rtw_secmicsetkey23a(&micdata, &stainfo->dot11tkiptxmickey.skey[0]); + } + + if (pframe[1] & 1) { /* ToDS == 1 */ + /* DA */ + rtw_secmicappend23a(&micdata, &pframe[16], 6); + if (pframe[1] & 2) /* From Ds == 1 */ + rtw_secmicappend23a(&micdata, + &pframe[24], 6); + else + rtw_secmicappend23a(&micdata, + &pframe[10], 6); + } else { /* ToDS == 0 */ + /* DA */ + rtw_secmicappend23a(&micdata, &pframe[4], 6); + if (pframe[1] & 2) /* From Ds == 1 */ + rtw_secmicappend23a(&micdata, + &pframe[16], 6); + else + rtw_secmicappend23a(&micdata, + &pframe[10], 6); + } + + /* if (pqospriv->qos_option == 1) */ + if (pattrib->qos_en) + priority[0] = (u8)pxmitframe->attrib.priority; + + rtw_secmicappend23a(&micdata, &priority[0], 4); + + payload = pframe; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; + curfragnum++) { + payload = (u8 *)RND4((unsigned long)payload); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("=== curfragnum =%d, pframe = 0x%.2x, " + "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x" + "%.2x, 0x%.2x, 0x%.2x,!!!\n", + curfragnum, *payload, *(payload + 1), + *(payload + 2), *(payload + 3), + *(payload + 4), *(payload + 5), + *(payload + 6), *(payload + 7))); + + payload = payload + pattrib->hdrlen + + pattrib->iv_len; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("curfragnum =%d pattrib->hdrlen =%d " + "pattrib->iv_len =%d", curfragnum, + pattrib->hdrlen, pattrib->iv_len)); + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz - + pattrib->hdrlen - + pattrib->iv_len - + ((pattrib->bswenc) ? + pattrib->icv_len : 0); + rtw_secmicappend23a(&micdata, payload, + length); + payload = payload + length; + } else { + length = pxmitpriv->frag_len - + pattrib->hdrlen - + pattrib->iv_len - + ((pattrib->bswenc) ? + pattrib->icv_len : 0); + rtw_secmicappend23a(&micdata, payload, + length); + payload = payload + length + + pattrib->icv_len; + RT_TRACE(_module_rtl871x_xmit_c_, + _drv_err_, + ("curfragnum =%d length =%d " + "pattrib->icv_len =%d", + curfragnum, length, + pattrib->icv_len)); + } + } + rtw_secgetmic23a(&micdata, &mic[0]); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("xmitframe_addmic: before add mic code!!\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("xmitframe_addmic: pattrib->last_txcmdsz =" + "%d!!!\n", pattrib->last_txcmdsz)); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]=" + "0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n" + "mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x " + ", mic[7]= 0x%.2x !!!!\n", mic[0], mic[1], + mic[2], mic[3], mic[4], mic[5], mic[6], + mic[7])); + /* add mic code and add the mic code length + in last_txcmdsz */ + + memcpy(payload, &mic[0], 8); + pattrib->last_txcmdsz += 8; + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("\n ======== last pkt ========\n")); + payload = payload - pattrib->last_txcmdsz + 8; + for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; + curfragnum = curfragnum + 8) + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + (" %.2x, %.2x, %.2x, %.2x, %.2x, " + " %.2x, %.2x, %.2x ", + *(payload + curfragnum), + *(payload + curfragnum + 1), + *(payload + curfragnum + 2), + *(payload + curfragnum + 3), + *(payload + curfragnum + 4), + *(payload + curfragnum + 5), + *(payload + curfragnum + 6), + *(payload + curfragnum + 7))); + } else { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("xmitframe_addmic: rtw_get_stainfo23a ==" + "NULL!!!\n")); + } + } + + return _SUCCESS; +} + +static s32 xmitframe_swencrypt(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + /* if ((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) */ + if (pattrib->bswenc) { + /* DBG_8723A("start xmitframe_swencrypt\n"); */ + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, + ("### xmitframe_swencrypt\n")); + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + rtw_wep_encrypt23a(padapter, pxmitframe); + break; + case _TKIP_: + rtw_tkip_encrypt23a(padapter, pxmitframe); + break; + case _AES_: + rtw_aes_encrypt23a(padapter, pxmitframe); + break; + default: + break; + } + + } else { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, + ("### xmitframe_hwencrypt\n")); + } + + return _SUCCESS; +} + +s32 rtw_make_wlanhdr23a(struct rtw_adapter *padapter, u8 *hdr, + struct pkt_attrib *pattrib) +{ + u16 *qc; + + struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + u8 qos_option = false; + int res = _SUCCESS; + u16 *fctrl = &pwlanhdr->frame_control; + + struct sta_info *psta; + + int bmcst = is_multicast_ether_addr(pattrib->ra); + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + if (bmcst) { + psta = rtw_get_bcmc_stainfo23a(padapter); + } else { + psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra); + } + } + + if (psta == NULL) { + DBG_8723A("%s, psta == NUL\n", __func__); + return _FAIL; + } + + if (!(psta->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + + memset(hdr, 0, WLANHDR_OFFSET); + + SetFrameSubType(fctrl, pattrib->subtype); + + if (pattrib->subtype & WIFI_DATA_TYPE) { + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) { + /* to_ds = 1, fr_ds = 0; */ + /* Data transfer to AP */ + SetToDs(fctrl); + memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); + memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); + + if (pqospriv->qos_option) + qos_option = true; + + } + else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) { + /* to_ds = 0, fr_ds = 1; */ + SetFrDs(fctrl); + memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); + + if (psta->qos_option) + qos_option = true; + } + else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { + memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); + + if (psta->qos_option) + qos_option = true; + } + else { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); + res = _FAIL; + goto exit; + } + if (pattrib->mdata) + SetMData(fctrl); + if (pattrib->encrypt) + SetPrivacy(fctrl); + if (qos_option) { + qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); + if (pattrib->priority) + SetPriority(qc, pattrib->priority); + SetEOSP(qc, pattrib->eosp); + SetAckpolicy(qc, pattrib->ack_policy); + } + /* TODO: fill HT Control Field */ + + /* Update Seq Num will be handled by f/w */ + if (psta) { + psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; + psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; + pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; + SetSeqNum(hdr, pattrib->seqnum); + /* check if enable ampdu */ + if (pattrib->ht_en && psta->htpriv.ampdu_enable) { + if (psta->htpriv.agg_enable_bitmap & CHKBIT(pattrib->priority)) + pattrib->ampdu_en = true; + } + /* re-check if enable ampdu by BA_starting_seqctrl */ + if (pattrib->ampdu_en) { + u16 tx_seq; + + tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; + + /* check BA_starting_seqctrl */ + if (SN_LESS(pattrib->seqnum, tx_seq)) { + /* DBG_8723A("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); */ + pattrib->ampdu_en = false;/* AGG BK */ + } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; + pattrib->ampdu_en = true;/* AGG EN */ + } else { + /* DBG_8723A("tx ampdu over run\n"); */ + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; + pattrib->ampdu_en = true;/* AGG EN */ + } + } + } + } +exit: + return res; +} + +s32 rtw_txframes_pending23a(struct rtw_adapter *padapter) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + return (!_rtw_queue_empty23a(&pxmitpriv->be_pending)) || + (!_rtw_queue_empty23a(&pxmitpriv->bk_pending)) || + (!_rtw_queue_empty23a(&pxmitpriv->vi_pending)) || + (!_rtw_queue_empty23a(&pxmitpriv->vo_pending)); +} + +s32 rtw_txframes_sta_ac_pending23a(struct rtw_adapter *padapter, + struct pkt_attrib *pattrib) +{ + struct sta_info *psta; + struct tx_servq *ptxservq; + int priority = pattrib->priority; + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]); + } + if (psta == NULL) { + DBG_8723A("%s, psta == NUL\n", __func__); + return 0; + } + if (!(psta->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, + psta->state); + return 0; + } + switch (priority) { + case 1: + case 2: + ptxservq = &psta->sta_xmitpriv.bk_q; + break; + case 4: + case 5: + ptxservq = &psta->sta_xmitpriv.vi_q; + break; + case 6: + case 7: + ptxservq = &psta->sta_xmitpriv.vo_q; + break; + case 0: + case 3: + default: + ptxservq = &psta->sta_xmitpriv.be_q; + break; + } + return ptxservq->qcnt; +} + +/* + * Calculate wlan 802.11 packet MAX size from pkt_attrib + * This function doesn't consider fragment case + */ +u32 rtw_calculate_wlan_pkt_size_by_attribue23a(struct pkt_attrib *pattrib) +{ + u32 len = 0; + + len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ + len += SNAP_SIZE + sizeof(u16); /* LLC */ + len += pattrib->pktlen; + if (pattrib->encrypt == _TKIP_) len += 8; /* MIC */ + len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ + + return len; +} + +/* + +This sub-routine will perform all the following: + +1. remove 802.3 header. +2. create wlan_header, based on the info in pxmitframe +3. append sta's iv/ext-iv +4. append LLC +5. move frag chunk from pframe to pxmitframe->mem +6. apply sw-encrypt, if necessary. + +*/ +s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, + struct xmit_frame *pxmitframe) +{ + struct pkt_file pktfile; + struct sta_info *psta; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; + unsigned long addr; + u8 *pframe, *mem_start; + u8 hw_hdr_offset; + u8 *pbuf_start; + + s32 bmcst = is_multicast_ether_addr(pattrib->ra); + s32 res = _SUCCESS; + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra); + } + + if (psta == NULL) { + DBG_8723A("%s, psta == NUL\n", __func__); + return _FAIL; + } + + if (!(psta->state &_FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + + if (pxmitframe->buf_addr == NULL) { + DBG_8723A("==> %s buf_addr == NULL\n", __func__); + return _FAIL; + } + + pbuf_start = pxmitframe->buf_addr; + + hw_hdr_offset = TXDESC_OFFSET; + + mem_start = pbuf_start + hw_hdr_offset; + + if (rtw_make_wlanhdr23a(padapter, mem_start, pattrib) == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("rtw_xmitframe_coalesce23a: rtw_make_wlanhdr23a " + "fail; drop pkt\n")); + res = _FAIL; + goto exit; + } + + _rtw_open_pktfile23a(pkt, &pktfile); + _rtw_pktfile_read23a(&pktfile, NULL, pattrib->pkt_hdrlen); + + frg_inx = 0; + frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ + + while (1) { + llc_sz = 0; + + mpdu_len = frg_len; + + pframe = mem_start; + + SetMFrag(mem_start); + + pframe += pattrib->hdrlen; + mpdu_len -= pattrib->hdrlen; + + /* adding icv, if necessary... */ + if (pattrib->iv_len) { + if (psta != NULL) { + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + break; + case _TKIP_: + if (bmcst) + TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + break; + case _AES_: + if (bmcst) + AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + AES_IV(pattrib->iv, psta->dot11txpn, 0); + break; + } + } + + memcpy(pframe, pattrib->iv, pattrib->iv_len); + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, + ("rtw_xmiaframe_coalesce23a: keyid =%d pattrib" + "->iv[3]=%.2x pframe =%.2x %.2x %.2x %.2x\n", + padapter->securitypriv.dot11PrivacyKeyIndex, + pattrib->iv[3], *pframe, *(pframe+1), + *(pframe+2), *(pframe+3))); + pframe += pattrib->iv_len; + mpdu_len -= pattrib->iv_len; + } + if (frg_inx == 0) { + llc_sz = rtw_put_snap23a(pframe, pattrib->ether_type); + pframe += llc_sz; + mpdu_len -= llc_sz; + } + + if ((pattrib->icv_len >0) && (pattrib->bswenc)) + mpdu_len -= pattrib->icv_len; + + if (bmcst) { + /* don't do fragment to broadcat/multicast packets */ + mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, pattrib->pktlen); + } else { + mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, mpdu_len); + } + pframe += mem_sz; + + if ((pattrib->icv_len >0) && (pattrib->bswenc)) { + memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + + frg_inx++; + + if (bmcst || (rtw_endofpktfile23a(&pktfile))) { + pattrib->nr_frags = frg_inx; + + pattrib->last_txcmdsz = pattrib->hdrlen + + pattrib->iv_len + + ((pattrib->nr_frags == 1) ? + llc_sz : 0) + + ((pattrib->bswenc) ? + pattrib->icv_len : 0) + mem_sz; + + ClearMFrag(mem_start); + + break; + } else { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); + } + + addr = (unsigned long)pframe; + + mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; + memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); + + } + + if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); + DBG_8723A("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); + res = _FAIL; + goto exit; + } + + xmitframe_swencrypt(padapter, pxmitframe); + + if (bmcst == false) + update_attrib_vcs_info(padapter, pxmitframe); + else + pattrib->vcs_mode = NONE_VCS; + +exit: + return res; +} + +/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header + * IEEE LLC/SNAP header contains 8 octets + * First 3 octets comprise the LLC portion + * SNAP portion, 5 octets, is divided into two fields: + * Organizationally Unique Identifier(OUI), 3 octets, + * type, defined by that organization, 2 octets. + */ +s32 rtw_put_snap23a(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + u8 *oui; + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == 0x8137 || h_proto == 0x80f3) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + *(u16 *)(data + SNAP_SIZE) = htons(h_proto); + return SNAP_SIZE + sizeof(u16); +} + +void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + uint protection; + u8 *perp; + int erp_len; + + switch (pxmitpriv->vcs_setting) { + case DISABLE_VCS: + pxmitpriv->vcs = NONE_VCS; + break; + case ENABLE_VCS: + break; + case AUTO_VCS: + default: + perp = rtw_get_ie23a(ie, _ERPINFO_IE_, &erp_len, ie_len); + if (perp == NULL) { + pxmitpriv->vcs = NONE_VCS; + } else { + protection = (*(perp + 2)) & BIT(1); + if (protection) { + if (pregistrypriv->vcs_type == RTS_CTS) + pxmitpriv->vcs = RTS_CTS; + else + pxmitpriv->vcs = CTS_TO_SELF; + } else { + pxmitpriv->vcs = NONE_VCS; + } + } + break; + } +} + +void rtw_count_tx_stats23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe, int sz) +{ + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { + pxmitpriv->tx_bytes += sz; + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod++; + + psta = pxmitframe->attrib.psta; + if (psta) { + pstats = &psta->sta_stats; + pstats->tx_pkts++; + pstats->tx_bytes += sz; + } + } +} + +struct xmit_buf *rtw_alloc_xmitbuf23a_ext(struct xmit_priv *pxmitpriv) +{ + unsigned long irqL; + struct xmit_buf *pxmitbuf = NULL; + struct list_head *phead; + struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; + + spin_lock_irqsave(&pfree_queue->lock, irqL); + + phead = get_list_head(pfree_queue); + + if (!list_empty(phead)) { + pxmitbuf = list_first_entry(phead, struct xmit_buf, list); + + list_del_init(&pxmitbuf->list); + + pxmitpriv->free_xmit_extbuf_cnt--; + pxmitbuf->priv_data = NULL; + pxmitbuf->ext_tag = true; + + if (pxmitbuf->sctx) { + DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); + } + } + + spin_unlock_irqrestore(&pfree_queue->lock, irqL); + + return pxmitbuf; +} + +s32 rtw_free_xmitbuf_ext23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + unsigned long irqL; + struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; + + if (pxmitbuf == NULL) + return _FAIL; + + spin_lock_irqsave(&pfree_queue->lock, irqL); + + list_del_init(&pxmitbuf->list); + + list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue)); + pxmitpriv->free_xmit_extbuf_cnt++; + + spin_unlock_irqrestore(&pfree_queue->lock, irqL); + + return _SUCCESS; +} + +struct xmit_buf *rtw_alloc_xmitbuf23a(struct xmit_priv *pxmitpriv) +{ + unsigned long irqL; + struct xmit_buf *pxmitbuf = NULL; + struct list_head *phead; + struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + /* DBG_8723A("+rtw_alloc_xmitbuf23a\n"); */ + + spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); + + phead = get_list_head(pfree_xmitbuf_queue); + + if (!list_empty(phead)) { + pxmitbuf = list_first_entry(phead, struct xmit_buf, list); + + list_del_init(&pxmitbuf->list); + + pxmitpriv->free_xmitbuf_cnt--; + pxmitbuf->priv_data = NULL; + pxmitbuf->ext_tag = false; + pxmitbuf->flags = XMIT_VO_QUEUE; + + if (pxmitbuf->sctx) { + DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); + } + } + + spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); + + return pxmitbuf; +} + +s32 rtw_free_xmitbuf23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + unsigned long irqL; + struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + /* DBG_8723A("+rtw_free_xmitbuf23a\n"); */ + + if (pxmitbuf == NULL) + return _FAIL; + + if (pxmitbuf->sctx) { + DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); + } + + if (pxmitbuf->ext_tag) { + rtw_free_xmitbuf_ext23a(pxmitpriv, pxmitbuf); + } else { + spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); + + list_del_init(&pxmitbuf->list); + + list_add_tail(&pxmitbuf->list, + get_list_head(pfree_xmitbuf_queue)); + + pxmitpriv->free_xmitbuf_cnt++; + spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); + } + + return _SUCCESS; +} + +static void rtw_init_xmitframe(struct xmit_frame *pxframe) +{ + if (pxframe != NULL) { + /* default value setting */ + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); + /* pxframe->attrib.psta = NULL; */ + + pxframe->frame_tag = DATA_FRAMETAG; + + pxframe->pkt = NULL; + pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */ + + pxframe->ack_report = 0; + } +} + +/* +Calling context: +1. OS_TXENTRY +2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) + +If we turn on USE_RXTHREAD, then, no need for critical section. +Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... + +Must be very very cautious... + +*/ +struct xmit_frame *rtw_alloc_xmitframe23a(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ +{ + /* + Please remember to use all the osdep_service api, + and lock/unlock or _enter/_exit critical to protect + pfree_xmit_queue + */ + + struct xmit_frame *pxframe = NULL; + struct list_head *plist, *phead; + struct rtw_queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; + + spin_lock_bh(&pfree_xmit_queue->lock); + + if (_rtw_queue_empty23a(pfree_xmit_queue) == true) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a:%d\n", pxmitpriv->free_xmitframe_cnt)); + pxframe = NULL; + } else { + phead = get_list_head(pfree_xmit_queue); + + plist = phead->next; + + pxframe = container_of(plist, struct xmit_frame, list); + + list_del_init(&pxframe->list); + pxmitpriv->free_xmitframe_cnt--; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); + } + + spin_unlock_bh(&pfree_xmit_queue->lock); + + rtw_init_xmitframe(pxframe); + + return pxframe; +} + +struct xmit_frame *rtw_alloc_xmitframe23a_ext(struct xmit_priv *pxmitpriv) +{ + struct xmit_frame *pxframe = NULL; + struct list_head *plist, *phead; + struct rtw_queue *queue = &pxmitpriv->free_xframe_ext_queue; + + spin_lock_bh(&queue->lock); + + if (_rtw_queue_empty23a(queue) == true) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext:%d\n", pxmitpriv->free_xframe_ext_cnt)); + pxframe = NULL; + } else { + phead = get_list_head(queue); + plist = phead->next; + pxframe = container_of(plist, struct xmit_frame, list); + + list_del_init(&pxframe->list); + pxmitpriv->free_xframe_ext_cnt--; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); + } + + spin_unlock_bh(&queue->lock); + + rtw_init_xmitframe(pxframe); + + return pxframe; +} + +s32 rtw_free_xmitframe23a(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) +{ + struct rtw_queue *queue = NULL; + struct rtw_adapter *padapter = pxmitpriv->adapter; + struct sk_buff *pndis_pkt = NULL; + + if (pxmitframe == NULL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe23a():pxmitframe == NULL!!!!!!!!!!\n")); + goto exit; + } + + if (pxmitframe->pkt) { + pndis_pkt = pxmitframe->pkt; + pxmitframe->pkt = NULL; + } + + if (pxmitframe->ext_tag == 0) + queue = &pxmitpriv->free_xmit_queue; + else if (pxmitframe->ext_tag == 1) + queue = &pxmitpriv->free_xframe_ext_queue; + + if (!queue) + goto check_pkt_complete; + spin_lock_bh(&queue->lock); + + list_del_init(&pxmitframe->list); + list_add_tail(&pxmitframe->list, get_list_head(queue)); + if (pxmitframe->ext_tag == 0) { + pxmitpriv->free_xmitframe_cnt++; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); + } else if (pxmitframe->ext_tag == 1) { + pxmitpriv->free_xframe_ext_cnt++; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xframe_ext_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); + } + + spin_unlock_bh(&queue->lock); + +check_pkt_complete: + + if (pndis_pkt) + rtw_os_pkt_complete23a(padapter, pndis_pkt); + +exit: + + return _SUCCESS; +} + +void rtw_free_xmitframe_queue23a(struct xmit_priv *pxmitpriv, + struct rtw_queue *pframequeue) +{ + struct list_head *plist, *phead, *ptmp; + struct xmit_frame *pxmitframe; + + spin_lock_bh(&pframequeue->lock); + + phead = get_list_head(pframequeue); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, struct xmit_frame, list); + + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + } + spin_unlock_bh(&pframequeue->lock); + +} + +s32 rtw_xmitframe_enqueue23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + if (rtw_xmit23a_classifier(padapter, pxmitframe) == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("rtw_xmitframe_enqueue23a: drop xmit pkt for " + "classifier fail\n")); + return _FAIL; + } + + return _SUCCESS; +} + +static struct xmit_frame * +dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, + struct tx_servq *ptxservq, struct rtw_queue *pframe_queue) +{ + struct list_head *phead; + struct xmit_frame *pxmitframe = NULL; + + phead = get_list_head(pframe_queue); + + if (!list_empty(phead)) { + pxmitframe = list_first_entry(phead, struct xmit_frame, list); + list_del_init(&pxmitframe->list); + ptxservq->qcnt--; + } + return pxmitframe; +} + +struct xmit_frame * +rtw_dequeue_xframe23a(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, + int entry) +{ + struct list_head *sta_plist, *sta_phead, *ptmp; + struct hw_xmit *phwxmit; + struct tx_servq *ptxservq = NULL; + struct rtw_queue *pframe_queue = NULL; + struct xmit_frame *pxmitframe = NULL; + struct rtw_adapter *padapter = pxmitpriv->adapter; + struct registry_priv *pregpriv = &padapter->registrypriv; + int i, inx[4]; + + inx[0] = 0; + inx[1] = 1; + inx[2] = 2; + inx[3] = 3; + if (pregpriv->wifi_spec == 1) { + int j; + + for (j = 0; j < 4; j++) + inx[j] = pxmitpriv->wmm_para_seq[j]; + } + + spin_lock_bh(&pxmitpriv->lock); + + for (i = 0; i < entry; i++) { + phwxmit = phwxmit_i + inx[i]; + + sta_phead = get_list_head(phwxmit->sta_queue); + + list_for_each_safe(sta_plist, ptmp, sta_phead) { + ptxservq = container_of(sta_plist, struct tx_servq, + tx_pending); + + pframe_queue = &ptxservq->sta_pending; + + pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); + + if (pxmitframe) { + phwxmit->accnt--; + + /* Remove sta node when there is no pending packets. */ + if (_rtw_queue_empty23a(pframe_queue)) /* must be done after get_next and before break */ + list_del_init(&ptxservq->tx_pending); + goto exit; + } + } + } +exit: + spin_unlock_bh(&pxmitpriv->lock); + return pxmitframe; +} + +struct tx_servq *rtw_get_sta_pending23a(struct rtw_adapter *padapter, struct sta_info *psta, int up, u8 *ac) +{ + struct tx_servq *ptxservq = NULL; + + switch (up) { + case 1: + case 2: + ptxservq = &psta->sta_xmitpriv.bk_q; + *(ac) = 3; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BK\n")); + break; + case 4: + case 5: + ptxservq = &psta->sta_xmitpriv.vi_q; + *(ac) = 1; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VI\n")); + break; + case 6: + case 7: + ptxservq = &psta->sta_xmitpriv.vo_q; + *(ac) = 0; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VO\n")); + break; + case 0: + case 3: + default: + ptxservq = &psta->sta_xmitpriv.be_q; + *(ac) = 2; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BE\n")); + break; + } + return ptxservq; +} + +/* + * Will enqueue pxmitframe to the proper queue, + * and indicate it to xx_pending list..... + */ +s32 rtw_xmit23a_classifier(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + struct sta_info *psta; + struct tx_servq *ptxservq; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + u8 ac_index; + int res = _SUCCESS; + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); + } + if (psta == NULL) { + res = _FAIL; + DBG_8723A("rtw_xmit23a_classifier: psta == NULL\n"); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("rtw_xmit23a_classifier: psta == NULL\n")); + goto exit; + } + if (!(psta->state & _FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, + psta->state); + return _FAIL; + } + ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority, + (u8 *)(&ac_index)); + + if (list_empty(&ptxservq->tx_pending)) { + list_add_tail(&ptxservq->tx_pending, + get_list_head(phwxmits[ac_index].sta_queue)); + } + + list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); + ptxservq->qcnt++; + phwxmits[ac_index].accnt++; +exit: + return res; +} + +void rtw_alloc_hwxmits23a(struct rtw_adapter *padapter) +{ + struct hw_xmit *hwxmits; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + int size; + + pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; + + size = sizeof(struct hw_xmit) * (pxmitpriv->hwxmit_entry + 1); + pxmitpriv->hwxmits = kzalloc(size, GFP_KERNEL); + + hwxmits = pxmitpriv->hwxmits; + + if (pxmitpriv->hwxmit_entry == 5) { + /* pxmitpriv->bmc_txqueue.head = 0; */ + /* hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; */ + hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; + + /* pxmitpriv->vo_txqueue.head = 0; */ + /* hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; */ + hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; + + /* pxmitpriv->vi_txqueue.head = 0; */ + /* hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; */ + hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; + + /* pxmitpriv->bk_txqueue.head = 0; */ + /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + + /* pxmitpriv->be_txqueue.head = 0; */ + /* hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; */ + hwxmits[4] .sta_queue = &pxmitpriv->be_pending; + + } else if (pxmitpriv->hwxmit_entry == 4) { + + /* pxmitpriv->vo_txqueue.head = 0; */ + /* hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; */ + hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; + + /* pxmitpriv->vi_txqueue.head = 0; */ + /* hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; */ + hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; + + /* pxmitpriv->be_txqueue.head = 0; */ + /* hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; */ + hwxmits[2] .sta_queue = &pxmitpriv->be_pending; + + /* pxmitpriv->bk_txqueue.head = 0; */ + /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + } else { + + } +} + +void rtw_free_hwxmits23a(struct rtw_adapter *padapter) +{ + struct hw_xmit *hwxmits; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + hwxmits = pxmitpriv->hwxmits; + kfree(hwxmits); +} + +void rtw_init_hwxmits23a(struct hw_xmit *phwxmit, int entry) +{ + int i; + + for (i = 0; i < entry; i++, phwxmit++) + phwxmit->accnt = 0; +} + +u32 rtw_get_ff_hwaddr23a(struct xmit_frame *pxmitframe) +{ + u32 addr; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + switch (pattrib->qsel) { + case 0: + case 3: + addr = BE_QUEUE_INX; + break; + case 1: + case 2: + addr = BK_QUEUE_INX; + break; + case 4: + case 5: + addr = VI_QUEUE_INX; + break; + case 6: + case 7: + addr = VO_QUEUE_INX; + break; + case 0x10: + addr = BCN_QUEUE_INX; + break; + case 0x11:/* BC/MC in PS (HIQ) */ + addr = HIGH_QUEUE_INX; + break; + case 0x12: + default: + addr = MGT_QUEUE_INX; + break; + } + + return addr; +} + +static void do_queue_select(struct rtw_adapter *padapter, struct pkt_attrib *pattrib) +{ + u8 qsel; + + qsel = pattrib->priority; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("### do_queue_select priority =%d , qsel = %d\n", + pattrib->priority, qsel)); + + pattrib->qsel = qsel; +} + +/* + * The main transmit(tx) entry + * + * Return + * 1 enqueue + * 0 success, hardware will handle this xmit frame(packet) + * <0 fail + */ +int rtw_xmit23a(struct rtw_adapter *padapter, struct sk_buff *skb) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_frame *pxmitframe = NULL; + s32 res; + + pxmitframe = rtw_alloc_xmitframe23a(pxmitpriv); + + if (pxmitframe == NULL) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, + ("rtw_xmit23a: no more pxmitframe\n")); + return -1; + } + + res = update_attrib(padapter, skb, &pxmitframe->attrib); + + if (res == _FAIL) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit23a: update attrib fail\n")); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + return -1; + } + pxmitframe->pkt = skb; + + rtw_led_control(padapter, LED_CTL_TX); + + do_queue_select(padapter, &pxmitframe->attrib); + +#ifdef CONFIG_8723AU_AP_MODE + spin_lock_bh(&pxmitpriv->lock); + if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) { + spin_unlock_bh(&pxmitpriv->lock); + return 1; + } + spin_unlock_bh(&pxmitpriv->lock); +#endif + + if (rtw_hal_xmit23a(padapter, pxmitframe) == false) + return 1; + + return 0; +} + +#if defined(CONFIG_8723AU_AP_MODE) + +int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + int ret = false; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + int bmcst = is_multicast_ether_addr(pattrib->ra); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) + return ret; + + if (pattrib->psta) { + psta = pattrib->psta; + } else { + DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__); + psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); + } + + if (psta == NULL) { + DBG_8723A("%s, psta == NUL\n", __func__); + return false; + } + + if (!(psta->state & _FW_LINKED)) { + DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, + psta->state); + return false; + } + + if (pattrib->triggered == 1) { + if (bmcst) + pattrib->qsel = 0x11;/* HIQ */ + return ret; + } + + if (bmcst) { + spin_lock_bh(&psta->sleep_q.lock); + + if (pstapriv->sta_dz_bitmap) { + /* if anyone sta is in ps mode */ + list_del_init(&pxmitframe->list); + + /* spin_lock_bh(&psta->sleep_q.lock); */ + + list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); + + psta->sleepq_len++; + + pstapriv->tim_bitmap |= BIT(0);/* */ + pstapriv->sta_dz_bitmap |= BIT(0); + + /* DBG_8723A("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ + + update_beacon23a(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ + + /* spin_unlock_bh(&psta->sleep_q.lock); */ + + ret = true; + + } + + spin_unlock_bh(&psta->sleep_q.lock); + + return ret; + + } + + spin_lock_bh(&psta->sleep_q.lock); + + if (psta->state&WIFI_SLEEP_STATE) { + u8 wmmps_ac = 0; + + if (pstapriv->sta_dz_bitmap & CHKBIT(psta->aid)) { + list_del_init(&pxmitframe->list); + + /* spin_lock_bh(&psta->sleep_q.lock); */ + + list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); + + psta->sleepq_len++; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(0); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(0); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(0); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(0); + break; + } + + if (wmmps_ac) + psta->sleepq_ac_len++; + + if (((psta->has_legacy_ac) && (!wmmps_ac)) || + ((!psta->has_legacy_ac) && (wmmps_ac))) { + pstapriv->tim_bitmap |= CHKBIT(psta->aid); + + if (psta->sleepq_len == 1) { + /* upate BCN for TIM IE */ + update_beacon23a(padapter, _TIM_IE_, NULL, false); + } + } + + /* spin_unlock_bh(&psta->sleep_q.lock); */ + + /* if (psta->sleepq_len > (NR_XMITFRAME>>3)) */ + /* */ + /* wakeup_sta_to_xmit23a(padapter, psta); */ + /* */ + + ret = true; + + } + + } + + spin_unlock_bh(&psta->sleep_q.lock); + + return ret; +} + +static void +dequeue_xmitframes_to_sleeping_queue(struct rtw_adapter *padapter, + struct sta_info *psta, + struct rtw_queue *pframequeue) +{ + int ret; + struct list_head *plist, *phead, *ptmp; + u8 ac_index; + struct tx_servq *ptxservq; + struct pkt_attrib *pattrib; + struct xmit_frame *pxmitframe; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + + phead = get_list_head(pframequeue); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, struct xmit_frame, list); + + ret = xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe); + + if (ret == true) { + pattrib = &pxmitframe->attrib; + + ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); + + ptxservq->qcnt--; + phwxmits[ac_index].accnt--; + } else { + /* DBG_8723A("xmitframe_enqueue_for_sleeping_sta23a return false\n"); */ + } + } +} + +void stop_sta_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct sta_info *psta_bmc; + struct sta_xmit_priv *pstaxmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + pstaxmitpriv = &psta->sta_xmitpriv; + + /* for BC/MC Frames */ + psta_bmc = rtw_get_bcmc_stainfo23a(padapter); + + spin_lock_bh(&pxmitpriv->lock); + + psta->state |= WIFI_SLEEP_STATE; + + pstapriv->sta_dz_bitmap |= CHKBIT(psta->aid); + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); + list_del_init(&pstaxmitpriv->vo_q.tx_pending); + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); + list_del_init(&pstaxmitpriv->vi_q.tx_pending); + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, + &pstaxmitpriv->be_q.sta_pending); + list_del_init(&pstaxmitpriv->be_q.tx_pending); + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, + &pstaxmitpriv->bk_q.sta_pending); + list_del_init(&pstaxmitpriv->bk_q.tx_pending); + + /* for BC/MC Frames */ + pstaxmitpriv = &psta_bmc->sta_xmitpriv; + dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, + &pstaxmitpriv->be_q.sta_pending); + list_del_init(&pstaxmitpriv->be_q.tx_pending); + + spin_unlock_bh(&pxmitpriv->lock); +} + +void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta) +{ + u8 update_mask = 0, wmmps_ac = 0; + struct sta_info *psta_bmc; + struct list_head *plist, *phead, *ptmp; + struct xmit_frame *pxmitframe = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + spin_lock_bh(&pxmitpriv->lock); + + phead = get_list_head(&psta->sleep_q); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, struct xmit_frame, list); + list_del_init(&pxmitframe->list); + + switch (pxmitframe->attrib.priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + psta->sleepq_len--; + if (psta->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + if (wmmps_ac) { + psta->sleepq_ac_len--; + if (psta->sleepq_ac_len > 0) { + pxmitframe->attrib.mdata = 1; + pxmitframe->attrib.eosp = 0; + } else { + pxmitframe->attrib.mdata = 0; + pxmitframe->attrib.eosp = 1; + } + } + + pxmitframe->attrib.triggered = 1; + rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe); + } + + if (psta->sleepq_len == 0) { + pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); + + /* upate BCN for TIM IE */ + update_mask = BIT(0); + + if (psta->state&WIFI_SLEEP_STATE) + psta->state ^= WIFI_SLEEP_STATE; + + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { + psta->expire_to = pstapriv->expire_to; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + } + + pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid); + } + + /* spin_unlock_bh(&psta->sleep_q.lock); */ + spin_unlock_bh(&pxmitpriv->lock); + + /* for BC/MC Frames */ + psta_bmc = rtw_get_bcmc_stainfo23a(padapter); + if (!psta_bmc) + return; + + if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { + /* no any sta in ps mode */ + spin_lock_bh(&pxmitpriv->lock); + + phead = get_list_head(&psta_bmc->sleep_q); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, struct xmit_frame, + list); + + list_del_init(&pxmitframe->list); + + psta_bmc->sleepq_len--; + if (psta_bmc->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe); + } + if (psta_bmc->sleepq_len == 0) { + pstapriv->tim_bitmap &= ~BIT(0); + pstapriv->sta_dz_bitmap &= ~BIT(0); + + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_mask |= BIT(1); + } + + /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */ + spin_unlock_bh(&pxmitpriv->lock); + } + + if (update_mask) + update_beacon23a(padapter, _TIM_IE_, NULL, false); +} + +void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter, + struct sta_info *psta) +{ + u8 wmmps_ac = 0; + struct list_head *plist, *phead, *ptmp; + struct xmit_frame *pxmitframe; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + /* spin_lock_bh(&psta->sleep_q.lock); */ + spin_lock_bh(&pxmitpriv->lock); + + phead = get_list_head(&psta->sleep_q); + + list_for_each_safe(plist, ptmp, phead) { + pxmitframe = container_of(plist, struct xmit_frame, list); + + switch (pxmitframe->attrib.priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + if (!wmmps_ac) + continue; + + list_del_init(&pxmitframe->list); + + psta->sleepq_len--; + psta->sleepq_ac_len--; + + if (psta->sleepq_ac_len > 0) { + pxmitframe->attrib.mdata = 1; + pxmitframe->attrib.eosp = 0; + } else { + pxmitframe->attrib.mdata = 0; + pxmitframe->attrib.eosp = 1; + } + + pxmitframe->attrib.triggered = 1; + + rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe); + + if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && + (wmmps_ac)) { + pstapriv->tim_bitmap &= ~CHKBIT(psta->aid); + + /* upate BCN for TIM IE */ + update_beacon23a(padapter, _TIM_IE_, NULL, false); + } + } + spin_unlock_bh(&pxmitpriv->lock); +} + +#endif + +void rtw_sctx_init23a(struct submit_ctx *sctx, int timeout_ms) +{ + sctx->timeout_ms = timeout_ms; + init_completion(&sctx->done); + sctx->status = RTW_SCTX_SUBMITTED; +} + +int rtw_sctx_wait23a(struct submit_ctx *sctx) +{ + int ret = _FAIL; + unsigned long expire; + int status = 0; + + expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : + MAX_SCHEDULE_TIMEOUT; + if (!wait_for_completion_timeout(&sctx->done, expire)) { + /* timeout, do something?? */ + status = RTW_SCTX_DONE_TIMEOUT; + DBG_8723A("%s timeout\n", __func__); + } else { + status = sctx->status; + } + + if (status == RTW_SCTX_DONE_SUCCESS) + ret = _SUCCESS; + + return ret; +} + +static bool rtw_sctx_chk_waring_status(int status) +{ + switch (status) { + case RTW_SCTX_DONE_UNKNOWN: + case RTW_SCTX_DONE_BUF_ALLOC: + case RTW_SCTX_DONE_BUF_FREE: + case RTW_SCTX_DONE_DRV_STOP: + case RTW_SCTX_DONE_DEV_REMOVE: + return true; + default: + return false; + } +} + +void rtw23a_sctx_done_err(struct submit_ctx **sctx, int status) +{ + if (*sctx) { + if (rtw_sctx_chk_waring_status(status)) + DBG_8723A("%s status:%d\n", __func__, status); + (*sctx)->status = status; + complete(&(*sctx)->done); + *sctx = NULL; + } +} + +void rtw_sctx_done23a(struct submit_ctx **sctx) +{ + rtw23a_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); +} + +int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms) +{ + struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; + + pack_tx_ops->timeout_ms = timeout_ms; + pack_tx_ops->status = RTW_SCTX_SUBMITTED; + + return rtw_sctx_wait23a(pack_tx_ops); +} + +void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status) +{ + struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; + + if (pxmitpriv->ack_tx) + rtw23a_sctx_done_err(&pack_tx_ops, status); + else + DBG_8723A("%s ack_tx not set\n", __func__); +} -- cgit v1.2.3 From f7c92d2cc2beb3367f244480300eaecdd9502932 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:39 -0500 Subject: staging: r8723au: Add source files for new driver - part 2 The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets. A driver for it has been available in a GitHub repo for several months. This commit contains the second part of the source files. The source is arbitrarily split to avoid E-mail files that are too large. Jes Sorensen at RedHat has made many improvements to the vendor code, and he has been doing the testing. I do not have access to this device. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c | 80 + drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c | 136 + .../staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c | 1063 ++ drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c | 726 ++ drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c | 188 + drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c | 259 + drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c | 163 + drivers/staging/rtl8723au/hal/hal_com.c | 881 ++ drivers/staging/rtl8723au/hal/hal_intf.c | 418 + drivers/staging/rtl8723au/hal/odm.c | 2090 ++++ drivers/staging/rtl8723au/hal/odm_HWConfig.c | 481 + drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c | 162 + drivers/staging/rtl8723au/hal/odm_debug.c | 24 + drivers/staging/rtl8723au/hal/odm_interface.c | 236 + .../staging/rtl8723au/hal/rtl8723a_bt-coexist.c | 11304 +++++++++++++++++++ drivers/staging/rtl8723au/hal/rtl8723a_cmd.c | 845 ++ drivers/staging/rtl8723au/hal/rtl8723a_dm.c | 273 + drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c | 3452 ++++++ drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c | 1197 ++ drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c | 515 + drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c | 69 + drivers/staging/rtl8723au/hal/rtl8723a_sreset.c | 73 + drivers/staging/rtl8723au/hal/rtl8723a_xmit.c | 52 + drivers/staging/rtl8723au/hal/rtl8723au_led.c | 113 + drivers/staging/rtl8723au/hal/rtl8723au_recv.c | 247 + drivers/staging/rtl8723au/hal/rtl8723au_xmit.c | 548 + drivers/staging/rtl8723au/hal/usb_halinit.c | 1834 +++ drivers/staging/rtl8723au/hal/usb_ops_linux.c | 848 ++ 28 files changed, 28277 insertions(+) create mode 100644 drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c create mode 100644 drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c create mode 100644 drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c create mode 100644 drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c create mode 100644 drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c create mode 100644 drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c create mode 100644 drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c create mode 100644 drivers/staging/rtl8723au/hal/hal_com.c create mode 100644 drivers/staging/rtl8723au/hal/hal_intf.c create mode 100644 drivers/staging/rtl8723au/hal/odm.c create mode 100644 drivers/staging/rtl8723au/hal/odm_HWConfig.c create mode 100644 drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c create mode 100644 drivers/staging/rtl8723au/hal/odm_debug.c create mode 100644 drivers/staging/rtl8723au/hal/odm_interface.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_cmd.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_dm.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_sreset.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723a_xmit.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723au_led.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723au_recv.c create mode 100644 drivers/staging/rtl8723au/hal/rtl8723au_xmit.c create mode 100644 drivers/staging/rtl8723au/hal/usb_halinit.c create mode 100644 drivers/staging/rtl8723au/hal/usb_ops_linux.c (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c b/drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c new file mode 100644 index 000000000000..747f86cddeb9 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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 "Hal8723PwrSeq.h" + +/* + drivers should parse below arrays and do the corresponding actions +*/ +/* 3 Power on Array */ +struct wlan_pwr_cfg rtl8723AU_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_CARDEMU_TO_ACT + RTL8723A_TRANS_END +}; + +/* 3 Radio off GPIO Array */ +struct wlan_pwr_cfg rtl8723AU_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_ACT_TO_CARDEMU + RTL8723A_TRANS_END +}; + +/* 3 Card Disable Array */ +struct wlan_pwr_cfg rtl8723AU_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_ACT_TO_CARDEMU + RTL8723A_TRANS_CARDEMU_TO_CARDDIS + RTL8723A_TRANS_END +}; + +/* 3 Card Enable Array */ +struct wlan_pwr_cfg rtl8723AU_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_CARDDIS_TO_CARDEMU + RTL8723A_TRANS_CARDEMU_TO_ACT + RTL8723A_TRANS_END +}; + +/* 3 Suspend Array */ +struct wlan_pwr_cfg rtl8723AU_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_ACT_TO_CARDEMU + RTL8723A_TRANS_CARDEMU_TO_SUS + RTL8723A_TRANS_END +}; + +/* 3 Resume Array */ +struct wlan_pwr_cfg rtl8723AU_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_SUS_TO_CARDEMU + RTL8723A_TRANS_CARDEMU_TO_ACT + RTL8723A_TRANS_END +}; + +/* 3 HWPDN Array */ +struct wlan_pwr_cfg rtl8723AU_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = { + RTL8723A_TRANS_ACT_TO_CARDEMU + RTL8723A_TRANS_CARDEMU_TO_PDN + RTL8723A_TRANS_END +}; + +/* 3 Enter LPS */ +struct wlan_pwr_cfg rtl8723AU_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STEPS+RTL8723A_TRANS_END_STEPS] = { + /* FW behavior */ + RTL8723A_TRANS_ACT_TO_LPS + RTL8723A_TRANS_END +}; + +/* 3 Leave LPS */ +struct wlan_pwr_cfg rtl8723AU_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS] = { + /* FW behavior */ + RTL8723A_TRANS_LPS_TO_ACT + RTL8723A_TRANS_END +}; diff --git a/drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c b/drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c new file mode 100644 index 000000000000..56833da63ced --- /dev/null +++ b/drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c @@ -0,0 +1,136 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/*Created on 2013/01/14, 15:51*/ +#include "odm_precomp.h" + +u32 Rtl8723UPHY_REG_Array_PG[Rtl8723UPHY_REG_Array_PGLength] = { + 0xe00, 0xffffffff, 0x0a0c0c0c, + 0xe04, 0xffffffff, 0x02040608, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0e, + 0xe14, 0xffffffff, 0x02040608, + 0xe18, 0xffffffff, 0x0a0c0d0e, + 0xe1c, 0xffffffff, 0x02040608, + 0x830, 0xffffffff, 0x0a0c0c0c, + 0x834, 0xffffffff, 0x02040608, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x0a0c0d0e, + 0x848, 0xffffffff, 0x02040608, + 0x84c, 0xffffffff, 0x0a0c0d0e, + 0x868, 0xffffffff, 0x02040608, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x06060606, + 0xe14, 0xffffffff, 0x00020406, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x06060606, + 0x848, 0xffffffff, 0x00020406, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + }; + +u32 Rtl8723UMACPHY_Array_PG[Rtl8723UMACPHY_Array_PGLength] = { + 0x0, +}; diff --git a/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c b/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c new file mode 100644 index 000000000000..9796f2e5c68f --- /dev/null +++ b/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c @@ -0,0 +1,1063 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/* Description: */ +/* This file is for 92CE/92CU dynamic mechanism only */ + +/* include files */ + +#include "odm_precomp.h" + +#define DPK_DELTA_MAPPING_NUM 13 +#define index_mapping_HP_NUM 15 +/* 091212 chiyokolin */ +static void +odm_TXPowerTrackingCallback_ThermalMeter_92C( + struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, delta_HP; + int ele_A, ele_D, TempCCk, X, value32; + int Y, ele_C; + s8 OFDM_index[2], CCK_index = 0, OFDM_index_old[2] = {0}; + s8 CCK_index_old = 0; + int i = 0; + bool is2T = IS_92C_SERIAL(pHalData->VersionID); + u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB*/ + u8 ThermalValue_HP_count = 0; + u32 ThermalValue_HP = 0; + s32 index_mapping_HP[index_mapping_HP_NUM] = { + 0, 1, 3, 4, 6, + 7, 9, 10, 12, 13, + 15, 16, 18, 19, 21 + }; + s8 index_HP; + + pdmpriv->TXPowerTrackingCallbackCnt++; /* cosa add for debug */ + pdmpriv->bTXPowerTrackingInit = true; + + if (pHalData->CurrentChannel == 14 && !pdmpriv->bCCKinCH14) + pdmpriv->bCCKinCH14 = true; + else if (pHalData->CurrentChannel != 14 && pdmpriv->bCCKinCH14) + pdmpriv->bCCKinCH14 = false; + + ThermalValue = (u8)PHY_QueryRFReg(Adapter, RF_PATH_A, RF_T_METER, + 0x1f);/* 0x24: RF Reg[4:0] */ + + rtl8723a_phy_ap_calibrate(Adapter, (ThermalValue - + pHalData->EEPROMThermalMeter)); + + if (is2T) + rf = 2; + else + rf = 1; + + if (ThermalValue) { + /* Query OFDM path A default setting */ + ele_D = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance, + bMaskDWord)&bMaskOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) { + /* find the index */ + if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) { + OFDM_index_old[0] = (u8)i; + break; + } + } + + /* Query OFDM path B default setting */ + if (is2T) { + ele_D = PHY_QueryBBReg(Adapter, rOFDM0_XBTxIQImbalance, + bMaskDWord)&bMaskOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) { /* find the index */ + if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) { + OFDM_index_old[1] = (u8)i; + break; + } + } + } + + /* Query CCK default setting From 0xa24 */ + TempCCk = PHY_QueryBBReg(Adapter, rCCK0_TxFilter2, + bMaskDWord)&bMaskCCK; + for (i = 0 ; i < CCK_TABLE_SIZE ; i++) { + if (pdmpriv->bCCKinCH14) { + if (!memcmp(&TempCCk, + &CCKSwingTable_Ch1423A[i][2], 4)) { + CCK_index_old = (u8)i; + break; + } + } else { + if (!memcmp(&TempCCk, + &CCKSwingTable_Ch1_Ch1323A[i][2], 4)) { + CCK_index_old = (u8)i; + break; + } + } + } + + if (!pdmpriv->ThermalValue) { + pdmpriv->ThermalValue = pHalData->EEPROMThermalMeter; + pdmpriv->ThermalValue_LCK = ThermalValue; + pdmpriv->ThermalValue_IQK = ThermalValue; + pdmpriv->ThermalValue_DPK = pHalData->EEPROMThermalMeter; + + for (i = 0; i < rf; i++) { + pdmpriv->OFDM_index_HP[i] = OFDM_index_old[i]; + pdmpriv->OFDM_index[i] = OFDM_index_old[i]; + } + pdmpriv->CCK_index_HP = CCK_index_old; + pdmpriv->CCK_index = CCK_index_old; + } + + if (pHalData->BoardType == BOARD_USB_High_PA) { + pdmpriv->ThermalValue_HP[pdmpriv->ThermalValue_HP_index] = ThermalValue; + pdmpriv->ThermalValue_HP_index++; + if (pdmpriv->ThermalValue_HP_index == HP_THERMAL_NUM) + pdmpriv->ThermalValue_HP_index = 0; + + for (i = 0; i < HP_THERMAL_NUM; i++) { + if (pdmpriv->ThermalValue_HP[i]) { + ThermalValue_HP += pdmpriv->ThermalValue_HP[i]; + ThermalValue_HP_count++; + } + } + + if (ThermalValue_HP_count) + ThermalValue = (u8)(ThermalValue_HP / ThermalValue_HP_count); + } + + delta = (ThermalValue > pdmpriv->ThermalValue) ? + (ThermalValue - pdmpriv->ThermalValue) : + (pdmpriv->ThermalValue - ThermalValue); + if (pHalData->BoardType == BOARD_USB_High_PA) { + if (pdmpriv->bDoneTxpower) + delta_HP = (ThermalValue > pdmpriv->ThermalValue) ? + (ThermalValue - pdmpriv->ThermalValue) : + (pdmpriv->ThermalValue - ThermalValue); + else + delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ? + (ThermalValue - pHalData->EEPROMThermalMeter) : + (pHalData->EEPROMThermalMeter - ThermalValue); + } else { + delta_HP = 0; + } + delta_LCK = (ThermalValue > pdmpriv->ThermalValue_LCK) ? + (ThermalValue - pdmpriv->ThermalValue_LCK) : + (pdmpriv->ThermalValue_LCK - ThermalValue); + delta_IQK = (ThermalValue > pdmpriv->ThermalValue_IQK) ? + (ThermalValue - pdmpriv->ThermalValue_IQK) : + (pdmpriv->ThermalValue_IQK - ThermalValue); + + if (delta_LCK > 1) { + pdmpriv->ThermalValue_LCK = ThermalValue; + rtl8723a_phy_lc_calibrate(Adapter); + } + + if ((delta > 0 || delta_HP > 0) && pdmpriv->TxPowerTrackControl) { + if (pHalData->BoardType == BOARD_USB_High_PA) { + pdmpriv->bDoneTxpower = true; + delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ? + (ThermalValue - pHalData->EEPROMThermalMeter) : + (pHalData->EEPROMThermalMeter - ThermalValue); + + if (delta_HP > index_mapping_HP_NUM-1) + index_HP = index_mapping_HP[index_mapping_HP_NUM-1]; + else + index_HP = index_mapping_HP[delta_HP]; + + if (ThermalValue > pHalData->EEPROMThermalMeter) { + /* set larger Tx power */ + for (i = 0; i < rf; i++) + OFDM_index[i] = pdmpriv->OFDM_index_HP[i] - index_HP; + CCK_index = pdmpriv->CCK_index_HP - index_HP; + } else { + for (i = 0; i < rf; i++) + OFDM_index[i] = pdmpriv->OFDM_index_HP[i] + index_HP; + CCK_index = pdmpriv->CCK_index_HP + index_HP; + } + + delta_HP = (ThermalValue > pdmpriv->ThermalValue) ? + (ThermalValue - pdmpriv->ThermalValue) : + (pdmpriv->ThermalValue - ThermalValue); + } else { + if (ThermalValue > pdmpriv->ThermalValue) { + for (i = 0; i < rf; i++) + pdmpriv->OFDM_index[i] -= delta; + pdmpriv->CCK_index -= delta; + } else { + for (i = 0; i < rf; i++) + pdmpriv->OFDM_index[i] += delta; + pdmpriv->CCK_index += delta; + } + } + + /* no adjust */ + if (pHalData->BoardType != BOARD_USB_High_PA) { + if (ThermalValue > pHalData->EEPROMThermalMeter) { + for (i = 0; i < rf; i++) + OFDM_index[i] = pdmpriv->OFDM_index[i]+1; + CCK_index = pdmpriv->CCK_index+1; + } else { + for (i = 0; i < rf; i++) + OFDM_index[i] = pdmpriv->OFDM_index[i]; + CCK_index = pdmpriv->CCK_index; + } + } + for (i = 0; i < rf; i++) { + if (OFDM_index[i] > (OFDM_TABLE_SIZE_92C-1)) + OFDM_index[i] = (OFDM_TABLE_SIZE_92C-1); + else if (OFDM_index[i] < OFDM_min_index) + OFDM_index[i] = OFDM_min_index; + } + + if (CCK_index > (CCK_TABLE_SIZE-1)) + CCK_index = (CCK_TABLE_SIZE-1); + else if (CCK_index < 0) + CCK_index = 0; + } + + if (pdmpriv->TxPowerTrackControl && (delta != 0 || delta_HP != 0)) { + /* Adujst OFDM Ant_A according to IQK result */ + ele_D = (OFDMSwingTable23A[OFDM_index[0]] & 0xFFC00000)>>22; + X = pdmpriv->RegE94; + Y = pdmpriv->RegE9C; + + if (X != 0) { + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D)>>8)&0x000003FF; + + /* new element C = element D x Y */ + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D)>>8)&0x000003FF; + + /* write new elements A, C, D to regC80 and regC94, element B is always 0 */ + value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A; + PHY_SetBBReg(Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, value32); + + value32 = ((X * ele_D)>>7)&0x01; + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT31, value32); + + value32 = ((Y * ele_D)>>7)&0x01; + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT29, value32); + } else { + PHY_SetBBReg(Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable23A[OFDM_index[0]]); + PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00); + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT31|BIT29, 0x00); + } + + /* Adjust CCK according to IQK result */ + if (!pdmpriv->bCCKinCH14) { + rtw_write8(Adapter, 0xa22, CCKSwingTable_Ch1_Ch1323A[CCK_index][0]); + rtw_write8(Adapter, 0xa23, CCKSwingTable_Ch1_Ch1323A[CCK_index][1]); + rtw_write8(Adapter, 0xa24, CCKSwingTable_Ch1_Ch1323A[CCK_index][2]); + rtw_write8(Adapter, 0xa25, CCKSwingTable_Ch1_Ch1323A[CCK_index][3]); + rtw_write8(Adapter, 0xa26, CCKSwingTable_Ch1_Ch1323A[CCK_index][4]); + rtw_write8(Adapter, 0xa27, CCKSwingTable_Ch1_Ch1323A[CCK_index][5]); + rtw_write8(Adapter, 0xa28, CCKSwingTable_Ch1_Ch1323A[CCK_index][6]); + rtw_write8(Adapter, 0xa29, CCKSwingTable_Ch1_Ch1323A[CCK_index][7]); + } else { + rtw_write8(Adapter, 0xa22, CCKSwingTable_Ch1423A[CCK_index][0]); + rtw_write8(Adapter, 0xa23, CCKSwingTable_Ch1423A[CCK_index][1]); + rtw_write8(Adapter, 0xa24, CCKSwingTable_Ch1423A[CCK_index][2]); + rtw_write8(Adapter, 0xa25, CCKSwingTable_Ch1423A[CCK_index][3]); + rtw_write8(Adapter, 0xa26, CCKSwingTable_Ch1423A[CCK_index][4]); + rtw_write8(Adapter, 0xa27, CCKSwingTable_Ch1423A[CCK_index][5]); + rtw_write8(Adapter, 0xa28, CCKSwingTable_Ch1423A[CCK_index][6]); + rtw_write8(Adapter, 0xa29, CCKSwingTable_Ch1423A[CCK_index][7]); + } + + if (is2T) { + ele_D = (OFDMSwingTable23A[(u8)OFDM_index[1]] & 0xFFC00000)>>22; + + /* new element A = element D x X */ + X = pdmpriv->RegEB4; + Y = pdmpriv->RegEBC; + + if (X != 0) { + if ((X & 0x00000200) != 0) /* consider minus */ + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D)>>8)&0x000003FF; + + /* new element C = element D x Y */ + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D)>>8)&0x00003FF; + + /* write new elements A, C, D to regC88 and regC9C, element B is always 0 */ + value32 = (ele_D<<22)|((ele_C&0x3F)<<16) | ele_A; + PHY_SetBBReg(Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + PHY_SetBBReg(Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, value32); + + value32 = ((X * ele_D)>>7)&0x01; + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT27, value32); + + value32 = ((Y * ele_D)>>7)&0x01; + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT25, value32); + } else { + PHY_SetBBReg(Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable23A[OFDM_index[1]]); + PHY_SetBBReg(Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); + PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT27|BIT25, 0x00); + } + } + + } + if (delta_IQK > 3) { + pdmpriv->ThermalValue_IQK = ThermalValue; + rtl8723a_phy_iq_calibrate(Adapter, false); + } + + /* update thermal meter value */ + if (pdmpriv->TxPowerTrackControl) + pdmpriv->ThermalValue = ThermalValue; + } + pdmpriv->TXPowercount = 0; +} + +/* Description: */ +/* - Dispatch TxPower Tracking direct call ONLY for 92s. */ +/* - We shall NOT schedule Workitem within PASSIVE LEVEL, which will cause system resource */ +/* leakage under some platform. */ +/* Assumption: */ +/* PASSIVE_LEVEL when this routine is called. */ +static void ODM_TXPowerTracking92CDirectCall(struct rtw_adapter *Adapter) +{ + odm_TXPowerTrackingCallback_ThermalMeter_92C(Adapter); +} + +static void odm_CheckTXPowerTracking_ThermalMeter(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dm_odm_t *podmpriv = &pHalData->odmpriv; + + if (!(podmpriv->SupportAbility & ODM_RF_TX_PWR_TRACK)) + return; + + if (!pdmpriv->TM_Trigger) { /* at least delay 1 sec */ + PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); + + pdmpriv->TM_Trigger = 1; + return; + } else { + ODM_TXPowerTracking92CDirectCall(Adapter); + pdmpriv->TM_Trigger = 0; + } +} + +void rtl8723a_odm_check_tx_power_tracking(struct rtw_adapter *Adapter) +{ + odm_CheckTXPowerTracking_ThermalMeter(Adapter); +} + +/* IQK */ +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 /* ms */ + +static u8 _PHY_PathA_IQK(struct rtw_adapter *pAdapter, bool configPathB) +{ + u32 regEAC, regE94, regE9C, regEA4; + u8 result = 0x00; + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + + /* path-A IQK setting */ + PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1f); + PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); + PHY_SetBBReg(pAdapter, rTx_IQK_PI_A, bMaskDWord, 0x82140102); + + PHY_SetBBReg(pAdapter, rRx_IQK_PI_A, bMaskDWord, configPathB ? 0x28160202 : + IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202:0x28160502); + + /* path-B IQK setting */ + if (configPathB) { + PHY_SetBBReg(pAdapter, rTx_IQK_Tone_B, bMaskDWord, 0x10008c22); + PHY_SetBBReg(pAdapter, rRx_IQK_Tone_B, bMaskDWord, 0x10008c22); + PHY_SetBBReg(pAdapter, rTx_IQK_PI_B, bMaskDWord, 0x82140102); + PHY_SetBBReg(pAdapter, rRx_IQK_PI_B, bMaskDWord, 0x28160202); + } + + /* LO calibration setting */ + PHY_SetBBReg(pAdapter, rIQK_AGC_Rsp, bMaskDWord, 0x001028d1); + + /* One shot, path A LOK & IQK */ + PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); + PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + + /* delay x ms */ + udelay(IQK_DELAY_TIME*1000);/* PlatformStallExecution(IQK_DELAY_TIME*1000); */ + + /* Check failed */ + regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord); + regE94 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord); + regE9C = PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord); + regEA4 = PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord); + + if (!(regEAC & BIT28) && + (((regE94 & 0x03FF0000)>>16) != 0x142) && + (((regE9C & 0x03FF0000)>>16) != 0x42)) + result |= 0x01; + else /* if Tx not OK, ignore Rx */ + return result; + + if (!(regEAC & BIT27) && /* if Tx is OK, check whether Rx is OK */ + (((regEA4 & 0x03FF0000)>>16) != 0x132) && + (((regEAC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else + DBG_8723A("Path A Rx IQK fail!!\n"); + return result; +} + +static u8 _PHY_PathB_IQK(struct rtw_adapter *pAdapter) +{ + u32 regEAC, regEB4, regEBC, regEC4, regECC; + u8 result = 0x00; + + /* One shot, path B LOK & IQK */ + PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000002); + PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000000); + + /* delay x ms */ + udelay(IQK_DELAY_TIME*1000); + + /* Check failed */ + regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord); + regEB4 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord); + regEBC = PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord); + regEC4 = PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord); + regECC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord); + + if (!(regEAC & BIT31) && + (((regEB4 & 0x03FF0000)>>16) != 0x142) && + (((regEBC & 0x03FF0000)>>16) != 0x42)) + result |= 0x01; + else + return result; + + if (!(regEAC & BIT30) && + (((regEC4 & 0x03FF0000)>>16) != 0x132) && + (((regECC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else + DBG_8723A("Path B Rx IQK fail!!\n"); + return result; +} + +static void _PHY_PathAFillIQKMatrix(struct rtw_adapter *pAdapter, + bool bIQKOK, + int result[][8], + u8 final_candidate, + bool bTxOnly + ) +{ + u32 Oldval_0, X, TX0_A, reg; + s32 Y, TX0_C; + + DBG_8723A("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed"); + + if (final_candidate == 0xFF) { + return; + } else if (bIQKOK) { + Oldval_0 = (PHY_QueryBBReg(pAdapter, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][0]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX0_A = (X * Oldval_0) >> 8; + PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); + PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0>>7) & 0x1)); + + Y = result[final_candidate][1]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + TX0_C = (Y * Oldval_0) >> 8; + PHY_SetBBReg(pAdapter, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); + PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); + PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0>>7) & 0x1)); + + if (bTxOnly) { + DBG_8723A("_PHY_PathAFillIQKMatrix only Tx OK\n"); + return; + } + + reg = result[final_candidate][2]; + PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][3] & 0x3F; + PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][3] >> 6) & 0xF; + PHY_SetBBReg(pAdapter, rOFDM0_RxIQExtAnta, 0xF0000000, reg); + } +} + +static void _PHY_PathBFillIQKMatrix(struct rtw_adapter *pAdapter, bool bIQKOK, int result[][8], u8 final_candidate, bool bTxOnly) +{ + u32 Oldval_1, X, TX1_A, reg; + s32 Y, TX1_C; + + DBG_8723A("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed"); + + if (final_candidate == 0xFF) { + return; + } else if (bIQKOK) { + Oldval_1 = (PHY_QueryBBReg(pAdapter, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][4]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX1_A = (X * Oldval_1) >> 8; + PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); + PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1>>7) & 0x1)); + + Y = result[final_candidate][5]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + TX1_C = (Y * Oldval_1) >> 8; + PHY_SetBBReg(pAdapter, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); + PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); + PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1>>7) & 0x1)); + + if (bTxOnly) + return; + + reg = result[final_candidate][6]; + PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][7] & 0x3F; + PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][7] >> 6) & 0xF; + PHY_SetBBReg(pAdapter, rOFDM0_AGCRSSITable, 0x0000F000, reg); + } +} + +static void _PHY_SaveADDARegisters(struct rtw_adapter *pAdapter, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum) +{ + u32 i; + + for (i = 0 ; i < RegisterNum ; i++) { + ADDABackup[i] = PHY_QueryBBReg(pAdapter, ADDAReg[i], bMaskDWord); + } +} + +static void _PHY_SaveMACRegisters(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup) +{ + u32 i; + + for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) { + MACBackup[i] = rtw_read8(pAdapter, MACReg[i]); + } + MACBackup[i] = rtw_read32(pAdapter, MACReg[i]); +} + +static void _PHY_ReloadADDARegisters(struct rtw_adapter *pAdapter, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum) +{ + u32 i; + + for (i = 0 ; i < RegiesterNum ; i++) { + PHY_SetBBReg(pAdapter, ADDAReg[i], bMaskDWord, ADDABackup[i]); + } +} + +static void _PHY_ReloadMACRegisters(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup) +{ + u32 i; + + for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) { + rtw_write8(pAdapter, MACReg[i], (u8)MACBackup[i]); + } + rtw_write32(pAdapter, MACReg[i], MACBackup[i]); +} + +static void _PHY_PathADDAOn(struct rtw_adapter *pAdapter, u32 *ADDAReg, bool isPathAOn, bool is2T) +{ + u32 pathOn; + u32 i; + + pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; + if (false == is2T) { + pathOn = 0x0bdb25a0; + PHY_SetBBReg(pAdapter, ADDAReg[0], bMaskDWord, 0x0b1b25a0); + } else { + PHY_SetBBReg(pAdapter, ADDAReg[0], bMaskDWord, pathOn); + } + + for (i = 1 ; i < IQK_ADDA_REG_NUM ; i++) + PHY_SetBBReg(pAdapter, ADDAReg[i], bMaskDWord, pathOn); +} + +static void _PHY_MACSettingCalibration(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup) +{ + u32 i = 0; + + rtw_write8(pAdapter, MACReg[i], 0x3F); + + for (i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++) { + rtw_write8(pAdapter, MACReg[i], (u8)(MACBackup[i]&(~BIT3))); + } + rtw_write8(pAdapter, MACReg[i], (u8)(MACBackup[i]&(~BIT5))); +} + +static void _PHY_PathAStandBy(struct rtw_adapter *pAdapter) +{ + PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x0); + PHY_SetBBReg(pAdapter, 0x840, bMaskDWord, 0x00010000); + PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000); +} + +static void _PHY_PIModeSwitch(struct rtw_adapter *pAdapter, bool PIMode) +{ + u32 mode; + + mode = PIMode ? 0x01000100 : 0x01000000; + PHY_SetBBReg(pAdapter, 0x820, bMaskDWord, mode); + PHY_SetBBReg(pAdapter, 0x828, bMaskDWord, mode); +} + +/* +return false => do IQK again +*/ +static bool _PHY_SimularityCompare(struct rtw_adapter *pAdapter, int result[][8], u8 c1, u8 c2) +{ + u32 i, j, diff, SimularityBitMap, bound = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ + bool bResult = true, is2T = IS_92C_SERIAL(pHalData->VersionID); + + if (is2T) + bound = 8; + else + bound = 4; + + SimularityBitMap = 0; + + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE) { + if ((i == 2 || i == 6) && !SimularityBitMap) { + if (result[c1][i]+result[c1][i+1] == 0) + final_candidate[(i/4)] = c2; + else if (result[c2][i]+result[c2][i+1] == 0) + final_candidate[(i/4)] = c1; + else + SimularityBitMap = SimularityBitMap|(1<dmpriv; + u32 i; + u8 PathAOK, PathBOK; + u32 ADDA_REG[IQK_ADDA_REG_NUM] = { + rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN + }; + + u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG + }; + + u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, + rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, + rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, + rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD + }; + + const u32 retryCount = 2; + + /* Note: IQ calibration must be performed after loading */ + /* PHY_REG.txt , and radio_a, radio_b.txt */ + + u32 bbvalue; + + if (t == 0) { + bbvalue = PHY_QueryBBReg(pAdapter, rFPGA0_RFMOD, bMaskDWord); + + /* Save ADDA parameters, turn Path A ADDA on */ + _PHY_SaveADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM); + _PHY_SaveMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup); + _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM); + } + _PHY_PathADDAOn(pAdapter, ADDA_REG, true, is2T); + + if (t == 0) + pdmpriv->bRfPiEnable = (u8)PHY_QueryBBReg(pAdapter, rFPGA0_XA_HSSIParameter1, BIT(8)); + + if (!pdmpriv->bRfPiEnable) { + /* Switch BB to PI mode to do IQ Calibration. */ + _PHY_PIModeSwitch(pAdapter, true); + } + + PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, BIT24, 0x00); + PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); + PHY_SetBBReg(pAdapter, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); + PHY_SetBBReg(pAdapter, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); + PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); + PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); + PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); + PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); + + if (is2T) { + PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); + PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); + } + + /* MAC settings */ + _PHY_MACSettingCalibration(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup); + + /* Page B init */ + PHY_SetBBReg(pAdapter, rConfig_AntA, bMaskDWord, 0x00080000); + + if (is2T) + PHY_SetBBReg(pAdapter, rConfig_AntB, bMaskDWord, 0x00080000); + + /* IQ calibration setting */ + PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000); + PHY_SetBBReg(pAdapter, rTx_IQK, bMaskDWord, 0x01007c00); + PHY_SetBBReg(pAdapter, rRx_IQK, bMaskDWord, 0x01004800); + + for (i = 0 ; i < retryCount ; i++) { + PathAOK = _PHY_PathA_IQK(pAdapter, is2T); + if (PathAOK == 0x03) { + DBG_8723A("Path A IQK Success!!\n"); + result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][2] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; + result[t][3] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; + break; + } else if (i == (retryCount-1) && PathAOK == 0x01) { + /* Tx IQK OK */ + DBG_8723A("Path A IQK Only Tx Success!!\n"); + + result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; + } + } + + if (0x00 == PathAOK) { + DBG_8723A("Path A IQK failed!!\n"); + } + + if (is2T) { + _PHY_PathAStandBy(pAdapter); + + /* Turn Path B ADDA on */ + _PHY_PathADDAOn(pAdapter, ADDA_REG, false, is2T); + + for (i = 0 ; i < retryCount ; i++) { + PathBOK = _PHY_PathB_IQK(pAdapter); + if (PathBOK == 0x03) { + DBG_8723A("Path B IQK Success!!\n"); + result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][6] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; + result[t][7] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; + break; + } else if (i == (retryCount - 1) && PathBOK == 0x01) { + /* Tx IQK OK */ + DBG_8723A("Path B Only Tx IQK Success!!\n"); + result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; + } + } + + if (0x00 == PathBOK) { + DBG_8723A("Path B IQK failed!!\n"); + } + } + + /* Back to BB mode, load original value */ + PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0); + + if (t != 0) { + if (!pdmpriv->bRfPiEnable) { + /* Switch back BB to SI mode after finish IQ Calibration. */ + _PHY_PIModeSwitch(pAdapter, false); + } + + /* Reload ADDA power saving parameters */ + _PHY_ReloadADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM); + + /* Reload MAC parameters */ + _PHY_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup); + + /* Reload BB parameters */ + _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM); + + /* Restore RX initial gain */ + PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); + if (is2T) { + PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); + } + + /* load 0xe30 IQC default value */ + PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); + PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); + + } +} + +static void _PHY_LCCalibrate(struct rtw_adapter *pAdapter, bool is2T) +{ + u8 tmpReg; + u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal; + + /* Check continuous TX and Packet TX */ + tmpReg = rtw_read8(pAdapter, 0xd03); + + if ((tmpReg&0x70) != 0) /* Deal with contisuous TX case */ + rtw_write8(pAdapter, 0xd03, tmpReg&0x8F); /* disable all continuous TX */ + else /* Deal with Packet TX case */ + rtw_write8(pAdapter, REG_TXPAUSE, 0xFF); /* block all queues */ + + if ((tmpReg&0x70) != 0) { + /* 1. Read original RF mode */ + /* Path-A */ + RF_Amode = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits); + + /* Path-B */ + if (is2T) + RF_Bmode = PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits); + + /* 2. Set RF mode = standby mode */ + /* Path-A */ + PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); + + /* Path-B */ + if (is2T) + PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); + } + + /* 3. Read RF reg18 */ + LC_Cal = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits); + + /* 4. Set LC calibration begin */ + PHY_SetRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); + + msleep(100); + + /* Restore original situation */ + if ((tmpReg&0x70) != 0) { /* Deal with contuous TX case */ + /* Path-A */ + rtw_write8(pAdapter, 0xd03, tmpReg); + PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); + + /* Path-B */ + if (is2T) + PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); + } else { /* Deal with Packet TX case */ + rtw_write8(pAdapter, REG_TXPAUSE, 0x00); + } +} + +/* Analog Pre-distortion calibration */ +#define APK_BB_REG_NUM 8 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +void rtl8723a_phy_iq_calibrate(struct rtw_adapter *pAdapter, bool bReCovery) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + s32 result[4][8]; /* last is final result */ + u8 i, final_candidate; + bool bPathAOK, bPathBOK; + s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4; + s32 RegECC, RegTmp = 0; + bool is12simular, is13simular, is23simular; + bool bStartContTx = false, bSingleTone = false; + bool bCarrierSuppression = false; + u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, + rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, + rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, + rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, + rOFDM0_RxIQExtAnta + }; + + /* ignore IQK when continuous Tx */ + if (bStartContTx || bSingleTone || bCarrierSuppression) + return; + + if (bReCovery) { + _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9); + return; + } + DBG_8723A("IQK:Start!!!\n"); + + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + bPathAOK = false; + bPathBOK = false; + is12simular = false; + is23simular = false; + is13simular = false; + + for (i = 0; i < 3; i++) { + if (IS_92C_SERIAL(pHalData->VersionID)) { + _PHY_IQCalibrate(pAdapter, result, i, true); + } else { + /* For 88C 1T1R */ + _PHY_IQCalibrate(pAdapter, result, i, false); + } + + if (i == 1) { + is12simular = _PHY_SimularityCompare(pAdapter, result, 0, 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + + if (i == 2) { + is13simular = _PHY_SimularityCompare(pAdapter, result, 0, 2); + if (is13simular) { + final_candidate = 0; + break; + } + + is23simular = _PHY_SimularityCompare(pAdapter, result, 1, 2); + if (is23simular) { + final_candidate = 1; + } else { + for (i = 0; i < 8; i++) + RegTmp += result[3][i]; + + if (RegTmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + + for (i = 0; i < 4; i++) { + RegE94 = result[i][0]; + RegE9C = result[i][1]; + RegEA4 = result[i][2]; + RegEAC = result[i][3]; + RegEB4 = result[i][4]; + RegEBC = result[i][5]; + RegEC4 = result[i][6]; + RegECC = result[i][7]; + } + + if (final_candidate != 0xff) { + RegE94 = result[final_candidate][0]; + pdmpriv->RegE94 = RegE94; + RegE9C = result[final_candidate][1]; + pdmpriv->RegE9C = RegE9C; + RegEA4 = result[final_candidate][2]; + RegEAC = result[final_candidate][3]; + RegEB4 = result[final_candidate][4]; + pdmpriv->RegEB4 = RegEB4; + RegEBC = result[final_candidate][5]; + pdmpriv->RegEBC = RegEBC; + RegEC4 = result[final_candidate][6]; + RegECC = result[final_candidate][7]; + DBG_8723A("IQK: final_candidate is %x\n", final_candidate); + DBG_8723A("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ", + RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC); + bPathAOK = bPathBOK = true; + } else { + RegE94 = RegEB4 = pdmpriv->RegE94 = pdmpriv->RegEB4 = 0x100; /* X default value */ + RegE9C = RegEBC = pdmpriv->RegE9C = pdmpriv->RegEBC = 0x0; /* Y default value */ + } + + if ((RegE94 != 0)/*&&(RegEA4 != 0)*/) + _PHY_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); + + if (IS_92C_SERIAL(pHalData->VersionID)) { + if ((RegEB4 != 0)/*&&(RegEC4 != 0)*/) + _PHY_PathBFillIQKMatrix(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); + } + + _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9); +} + +void rtl8723a_phy_lc_calibrate(struct rtw_adapter *pAdapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + struct mlme_ext_priv *pmlmeext = &pAdapter->mlmeextpriv; + bool bStartContTx = false, bSingleTone = false, bCarrierSuppression = false; + + /* ignore IQK when continuous Tx */ + if (bStartContTx || bSingleTone || bCarrierSuppression) + return; + + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) + return; + + if (IS_92C_SERIAL(pHalData->VersionID)) { + _PHY_LCCalibrate(pAdapter, true); + } else { + /* For 88C 1T1R */ + _PHY_LCCalibrate(pAdapter, false); + } +} + +void +rtl8723a_phy_ap_calibrate(struct rtw_adapter *pAdapter, char delta) +{ +} diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c new file mode 100644 index 000000000000..294e6a6c60db --- /dev/null +++ b/drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c @@ -0,0 +1,726 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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 "odm_precomp.h" + +static bool CheckCondition(const u32 Condition, const u32 Hex) +{ + u32 _board = (Hex & 0x000000FF); + u32 _interface = (Hex & 0x0000FF00) >> 8; + u32 _platform = (Hex & 0x00FF0000) >> 16; + u32 cond = Condition; + + if (Condition == 0xCDCDCDCD) + return true; + + cond = Condition & 0x000000FF; + if ((_board == cond) && cond != 0x00) + return false; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ((_interface & cond) == 0 && cond != 0x07) + return false; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ((_platform & cond) == 0 && cond != 0x0F) + return false; + return true; +} + +/****************************************************************************** +* AGC_TAB_1T.TXT +******************************************************************************/ + +static u32 Array_AGC_TAB_1T_8723A[] = { + 0xC78, 0x7B000001, + 0xC78, 0x7B010001, + 0xC78, 0x7B020001, + 0xC78, 0x7B030001, + 0xC78, 0x7B040001, + 0xC78, 0x7B050001, + 0xC78, 0x7A060001, + 0xC78, 0x79070001, + 0xC78, 0x78080001, + 0xC78, 0x77090001, + 0xC78, 0x760A0001, + 0xC78, 0x750B0001, + 0xC78, 0x740C0001, + 0xC78, 0x730D0001, + 0xC78, 0x720E0001, + 0xC78, 0x710F0001, + 0xC78, 0x70100001, + 0xC78, 0x6F110001, + 0xC78, 0x6E120001, + 0xC78, 0x6D130001, + 0xC78, 0x6C140001, + 0xC78, 0x6B150001, + 0xC78, 0x6A160001, + 0xC78, 0x69170001, + 0xC78, 0x68180001, + 0xC78, 0x67190001, + 0xC78, 0x661A0001, + 0xC78, 0x651B0001, + 0xC78, 0x641C0001, + 0xC78, 0x631D0001, + 0xC78, 0x621E0001, + 0xC78, 0x611F0001, + 0xC78, 0x60200001, + 0xC78, 0x49210001, + 0xC78, 0x48220001, + 0xC78, 0x47230001, + 0xC78, 0x46240001, + 0xC78, 0x45250001, + 0xC78, 0x44260001, + 0xC78, 0x43270001, + 0xC78, 0x42280001, + 0xC78, 0x41290001, + 0xC78, 0x402A0001, + 0xC78, 0x262B0001, + 0xC78, 0x252C0001, + 0xC78, 0x242D0001, + 0xC78, 0x232E0001, + 0xC78, 0x222F0001, + 0xC78, 0x21300001, + 0xC78, 0x20310001, + 0xC78, 0x06320001, + 0xC78, 0x05330001, + 0xC78, 0x04340001, + 0xC78, 0x03350001, + 0xC78, 0x02360001, + 0xC78, 0x01370001, + 0xC78, 0x00380001, + 0xC78, 0x00390001, + 0xC78, 0x003A0001, + 0xC78, 0x003B0001, + 0xC78, 0x003C0001, + 0xC78, 0x003D0001, + 0xC78, 0x003E0001, + 0xC78, 0x003F0001, + 0xC78, 0x7B400001, + 0xC78, 0x7B410001, + 0xC78, 0x7B420001, + 0xC78, 0x7B430001, + 0xC78, 0x7B440001, + 0xC78, 0x7B450001, + 0xC78, 0x7A460001, + 0xC78, 0x79470001, + 0xC78, 0x78480001, + 0xC78, 0x77490001, + 0xC78, 0x764A0001, + 0xC78, 0x754B0001, + 0xC78, 0x744C0001, + 0xC78, 0x734D0001, + 0xC78, 0x724E0001, + 0xC78, 0x714F0001, + 0xC78, 0x70500001, + 0xC78, 0x6F510001, + 0xC78, 0x6E520001, + 0xC78, 0x6D530001, + 0xC78, 0x6C540001, + 0xC78, 0x6B550001, + 0xC78, 0x6A560001, + 0xC78, 0x69570001, + 0xC78, 0x68580001, + 0xC78, 0x67590001, + 0xC78, 0x665A0001, + 0xC78, 0x655B0001, + 0xC78, 0x645C0001, + 0xC78, 0x635D0001, + 0xC78, 0x625E0001, + 0xC78, 0x615F0001, + 0xC78, 0x60600001, + 0xC78, 0x49610001, + 0xC78, 0x48620001, + 0xC78, 0x47630001, + 0xC78, 0x46640001, + 0xC78, 0x45650001, + 0xC78, 0x44660001, + 0xC78, 0x43670001, + 0xC78, 0x42680001, + 0xC78, 0x41690001, + 0xC78, 0x406A0001, + 0xC78, 0x266B0001, + 0xC78, 0x256C0001, + 0xC78, 0x246D0001, + 0xC78, 0x236E0001, + 0xC78, 0x226F0001, + 0xC78, 0x21700001, + 0xC78, 0x20710001, + 0xC78, 0x06720001, + 0xC78, 0x05730001, + 0xC78, 0x04740001, + 0xC78, 0x03750001, + 0xC78, 0x02760001, + 0xC78, 0x01770001, + 0xC78, 0x00780001, + 0xC78, 0x00790001, + 0xC78, 0x007A0001, + 0xC78, 0x007B0001, + 0xC78, 0x007C0001, + 0xC78, 0x007D0001, + 0xC78, 0x007E0001, + 0xC78, 0x007F0001, + 0xC78, 0x3800001E, + 0xC78, 0x3801001E, + 0xC78, 0x3802001E, + 0xC78, 0x3803001E, + 0xC78, 0x3804001E, + 0xC78, 0x3805001E, + 0xC78, 0x3806001E, + 0xC78, 0x3807001E, + 0xC78, 0x3808001E, + 0xC78, 0x3C09001E, + 0xC78, 0x3E0A001E, + 0xC78, 0x400B001E, + 0xC78, 0x440C001E, + 0xC78, 0x480D001E, + 0xC78, 0x4C0E001E, + 0xC78, 0x500F001E, + 0xC78, 0x5210001E, + 0xC78, 0x5611001E, + 0xC78, 0x5A12001E, + 0xC78, 0x5E13001E, + 0xC78, 0x6014001E, + 0xC78, 0x6015001E, + 0xC78, 0x6016001E, + 0xC78, 0x6217001E, + 0xC78, 0x6218001E, + 0xC78, 0x6219001E, + 0xC78, 0x621A001E, + 0xC78, 0x621B001E, + 0xC78, 0x621C001E, + 0xC78, 0x621D001E, + 0xC78, 0x621E001E, + 0xC78, 0x621F001E, +}; + +#define READ_NEXT_PAIR(v1, v2, i) \ + do { \ + i += 2; v1 = Array[i]; v2 = Array[i+1]; \ + } while (0) + +void ODM_ReadAndConfig_AGC_TAB_1T_8723A(struct dm_odm_t *pDM_Odm) +{ + + u32 hex; + u32 i; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_AGC_TAB_1T_8723A)/sizeof(u32); + u32 *Array = Array_AGC_TAB_1T_8723A; + + hex = board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 2) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + + /* This (offset, data) pair meets the condition. */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigBB_AGC_8723A(pDM_Odm, v1, bMaskDWord, v2); + continue; + } else { + if (!CheckCondition(Array[i], hex)) { + /* Discard the following (offset, data) pairs. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2 */ + } else { + /* Configure matched pairs and skip to end of if-else. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) { + odm_ConfigBB_AGC_8723A(pDM_Odm, v1, bMaskDWord, v2); + READ_NEXT_PAIR(v1, v2, i); + } + while (v2 != 0xDEAD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } +} + +/****************************************************************************** +* PHY_REG_1T.TXT +******************************************************************************/ + +static u32 Array_PHY_REG_1T_8723A[] = { + 0x800, 0x80040000, + 0x804, 0x00000003, + 0x808, 0x0000FC00, + 0x80C, 0x0000000A, + 0x810, 0x10001331, + 0x814, 0x020C3D10, + 0x818, 0x02200385, + 0x81C, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x00000000, + 0x82C, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83C, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84C, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569A569A, + 0x85C, 0x001B25A4, + 0x860, 0x66F60110, + 0x864, 0x061F0130, + 0x868, 0x00000000, + 0x86C, 0x32323200, + 0x870, 0x07000760, + 0x874, 0x22004000, + 0x878, 0x00000808, + 0x87C, 0x00000000, + 0x880, 0xC0083070, + 0x884, 0x000004D5, + 0x888, 0x00000000, + 0x88C, 0xCCC000C0, + 0x890, 0x00000800, + 0x894, 0xFFFFFFFE, + 0x898, 0x40302010, + 0x89C, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90C, 0x81121111, + 0xA00, 0x00D047C8, + 0xA04, 0x80FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E68120F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00D30000, + 0xA70, 0x101FBF00, + 0xA74, 0x00000007, + 0xA78, 0x00000900, + 0xC00, 0x48071D40, + 0xC04, 0x03A05611, + 0xC08, 0x000000E4, + 0xC0C, 0x6C6C6C6C, + 0xC10, 0x08800000, + 0xC14, 0x40000100, + 0xC18, 0x08800000, + 0xC1C, 0x40000100, + 0xC20, 0x00000000, + 0xC24, 0x00000000, + 0xC28, 0x00000000, + 0xC2C, 0x00000000, + 0xC30, 0x69E9AC44, + 0xFF0F011F, 0xABCD, + 0xC34, 0x469652CF, + 0xCDCDCDCD, 0xCDCD, + 0xC34, 0x469652AF, + 0xFF0F011F, 0xDEAD, + 0xC38, 0x49795994, + 0xC3C, 0x0A97971C, + 0xC40, 0x1F7C403F, + 0xC44, 0x000100B7, + 0xC48, 0xEC020107, + 0xC4C, 0x007F037F, + 0xC50, 0x69543420, + 0xC54, 0x43BC0094, + 0xC58, 0x69543420, + 0xC5C, 0x433C0094, + 0xC60, 0x00000000, + 0xFF0F011F, 0xABCD, + 0xC64, 0x7116848B, + 0xCDCDCDCD, 0xCDCD, + 0xC64, 0x7112848B, + 0xFF0F011F, 0xDEAD, + 0xC68, 0x47C00BFF, + 0xC6C, 0x00000036, + 0xC70, 0x2C7F000D, + 0xC74, 0x018610DB, + 0xC78, 0x0000001F, + 0xC7C, 0x00B91612, + 0xC80, 0x40000100, + 0xC84, 0x20F60000, + 0xC88, 0x40000100, + 0xC8C, 0x20200000, + 0xC90, 0x00121820, + 0xC94, 0x00000000, + 0xC98, 0x00121820, + 0xC9C, 0x00007F7F, + 0xCA0, 0x00000000, + 0xCA4, 0x00000080, + 0xCA8, 0x00000000, + 0xCAC, 0x00000000, + 0xCB0, 0x00000000, + 0xCB4, 0x00000000, + 0xCB8, 0x00000000, + 0xCBC, 0x28000000, + 0xCC0, 0x00000000, + 0xCC4, 0x00000000, + 0xCC8, 0x00000000, + 0xCCC, 0x00000000, + 0xCD0, 0x00000000, + 0xCD4, 0x00000000, + 0xCD8, 0x64B22427, + 0xCDC, 0x00766932, + 0xCE0, 0x00222222, + 0xCE4, 0x00000000, + 0xCE8, 0x37644302, + 0xCEC, 0x2F97D40C, + 0xD00, 0x00080740, + 0xD04, 0x00020401, + 0xD08, 0x0000907F, + 0xD0C, 0x20010201, + 0xD10, 0xA0633333, + 0xD14, 0x3333BC43, + 0xD18, 0x7A8F5B6B, + 0xD2C, 0xCC979975, + 0xD30, 0x00000000, + 0xD34, 0x80608000, + 0xD38, 0x00000000, + 0xD3C, 0x00027293, + 0xD40, 0x00000000, + 0xD44, 0x00000000, + 0xD48, 0x00000000, + 0xD4C, 0x00000000, + 0xD50, 0x6437140A, + 0xD54, 0x00000000, + 0xD58, 0x00000000, + 0xD5C, 0x30032064, + 0xD60, 0x4653DE68, + 0xD64, 0x04518A3C, + 0xD68, 0x00002101, + 0xD6C, 0x2A201C16, + 0xD70, 0x1812362E, + 0xD74, 0x322C2220, + 0xD78, 0x000E3C24, + 0xE00, 0x2A2A2A2A, + 0xE04, 0x2A2A2A2A, + 0xE08, 0x03902A2A, + 0xE10, 0x2A2A2A2A, + 0xE14, 0x2A2A2A2A, + 0xE18, 0x2A2A2A2A, + 0xE1C, 0x2A2A2A2A, + 0xE28, 0x00000000, + 0xE30, 0x1000DC1F, + 0xE34, 0x10008C1F, + 0xE38, 0x02140102, + 0xE3C, 0x681604C2, + 0xE40, 0x01007C00, + 0xE44, 0x01004800, + 0xE48, 0xFB000000, + 0xE4C, 0x000028D1, + 0xE50, 0x1000DC1F, + 0xE54, 0x10008C1F, + 0xE58, 0x02140102, + 0xE5C, 0x28160D05, + 0xE60, 0x00000008, + 0xE68, 0x001B25A4, + 0xE6C, 0x631B25A0, + 0xE70, 0x631B25A0, + 0xE74, 0x081B25A0, + 0xE78, 0x081B25A0, + 0xE7C, 0x081B25A0, + 0xE80, 0x081B25A0, + 0xE84, 0x631B25A0, + 0xE88, 0x081B25A0, + 0xE8C, 0x631B25A0, + 0xED0, 0x631B25A0, + 0xED4, 0x631B25A0, + 0xED8, 0x631B25A0, + 0xEDC, 0x001B25A0, + 0xEE0, 0x001B25A0, + 0xEEC, 0x6B1B25A0, + 0xF14, 0x00000003, + 0xF4C, 0x00000000, + 0xF00, 0x00000300, +}; + +void ODM_ReadAndConfig_PHY_REG_1T_8723A(struct dm_odm_t *pDM_Odm) +{ + u32 hex = 0; + u32 i = 0; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_PHY_REG_1T_8723A)/sizeof(u32); + u32 *Array = Array_PHY_REG_1T_8723A; + + hex += board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 2) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + + /* This (offset, data) pair meets the condition. */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2); + continue; + } else { + if (!CheckCondition(Array[i], hex)) { + /* Discard the following (offset, data) pairs. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2 */ + } else { + /* Configure matched pairs and skip to end of if-else. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) { + odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2); + READ_NEXT_PAIR(v1, v2, i); + } + while (v2 != 0xDEAD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } +} + +/****************************************************************************** +* PHY_REG_MP.TXT +******************************************************************************/ + +static u32 Array_PHY_REG_MP_8723A[] = { + 0xC30, 0x69E9AC4A, + 0xC3C, 0x0A979718, +}; + +void ODM_ReadAndConfig_PHY_REG_MP_8723A(struct dm_odm_t *pDM_Odm) +{ + u32 hex = 0; + u32 i = 0; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_PHY_REG_MP_8723A)/sizeof(u32); + u32 *Array = Array_PHY_REG_MP_8723A; + + hex += board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 2) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + + /* This (offset, data) pair meets the condition. */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2); + continue; + } else { + if (!CheckCondition(Array[i], hex)) { + /* Discard the following (offset, data) pairs. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2 */ + } else { + /* Configure matched pairs and skip to end of if-else. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) { + odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2); + READ_NEXT_PAIR(v1, v2, i); + } + while (v2 != 0xDEAD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } +} + +/****************************************************************************** +* PHY_REG_PG.TXT +******************************************************************************/ + +static u32 Array_PHY_REG_PG_8723A[] = { + 0xE00, 0xFFFFFFFF, 0x0A0C0C0C, + 0xE04, 0xFFFFFFFF, 0x02040608, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x0A0C0D0E, + 0xE14, 0xFFFFFFFF, 0x02040608, + 0xE18, 0xFFFFFFFF, 0x0A0C0D0E, + 0xE1C, 0xFFFFFFFF, 0x02040608, + 0x830, 0xFFFFFFFF, 0x0A0C0C0C, + 0x834, 0xFFFFFFFF, 0x02040608, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x0A0C0D0E, + 0x848, 0xFFFFFFFF, 0x02040608, + 0x84C, 0xFFFFFFFF, 0x0A0C0D0E, + 0x868, 0xFFFFFFFF, 0x02040608, + 0xE00, 0xFFFFFFFF, 0x00000000, + 0xE04, 0xFFFFFFFF, 0x00000000, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x00000000, + 0xE14, 0xFFFFFFFF, 0x00000000, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x00000000, + 0x834, 0xFFFFFFFF, 0x00000000, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x00000000, + 0x848, 0xFFFFFFFF, 0x00000000, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, + 0xE00, 0xFFFFFFFF, 0x04040404, + 0xE04, 0xFFFFFFFF, 0x00020204, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x06060606, + 0xE14, 0xFFFFFFFF, 0x00020406, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x04040404, + 0x834, 0xFFFFFFFF, 0x00020204, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x06060606, + 0x848, 0xFFFFFFFF, 0x00020406, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, + 0xE00, 0xFFFFFFFF, 0x00000000, + 0xE04, 0xFFFFFFFF, 0x00000000, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x00000000, + 0xE14, 0xFFFFFFFF, 0x00000000, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x00000000, + 0x834, 0xFFFFFFFF, 0x00000000, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x00000000, + 0x848, 0xFFFFFFFF, 0x00000000, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, + 0xE00, 0xFFFFFFFF, 0x00000000, + 0xE04, 0xFFFFFFFF, 0x00000000, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x00000000, + 0xE14, 0xFFFFFFFF, 0x00000000, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x00000000, + 0x834, 0xFFFFFFFF, 0x00000000, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x00000000, + 0x848, 0xFFFFFFFF, 0x00000000, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, + 0xE00, 0xFFFFFFFF, 0x04040404, + 0xE04, 0xFFFFFFFF, 0x00020204, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x00000000, + 0xE14, 0xFFFFFFFF, 0x00000000, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x04040404, + 0x834, 0xFFFFFFFF, 0x00020204, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x00000000, + 0x848, 0xFFFFFFFF, 0x00000000, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, + 0xE00, 0xFFFFFFFF, 0x00000000, + 0xE04, 0xFFFFFFFF, 0x00000000, + 0xE08, 0x0000FF00, 0x00000000, + 0x86C, 0xFFFFFF00, 0x00000000, + 0xE10, 0xFFFFFFFF, 0x00000000, + 0xE14, 0xFFFFFFFF, 0x00000000, + 0xE18, 0xFFFFFFFF, 0x00000000, + 0xE1C, 0xFFFFFFFF, 0x00000000, + 0x830, 0xFFFFFFFF, 0x00000000, + 0x834, 0xFFFFFFFF, 0x00000000, + 0x838, 0xFFFFFF00, 0x00000000, + 0x86C, 0x000000FF, 0x00000000, + 0x83C, 0xFFFFFFFF, 0x00000000, + 0x848, 0xFFFFFFFF, 0x00000000, + 0x84C, 0xFFFFFFFF, 0x00000000, + 0x868, 0xFFFFFFFF, 0x00000000, +}; + +void ODM_ReadAndConfig_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm) +{ + u32 hex = 0; + u32 i = 0; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_PHY_REG_PG_8723A)/sizeof(u32); + u32 *Array = Array_PHY_REG_PG_8723A; + + hex += board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 3) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + u32 v3 = Array[i+2]; + + /* this line is a line of pure_body */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigBB_PHY_REG_PG_8723A(pDM_Odm, v1, v2, v3); + continue; + } else { /* this line is the start of branch */ + if (!CheckCondition(Array[i], hex)) { + /* don't need the hw_body */ + i += 2; /* skip the pair of expression */ + v1 = Array[i]; + v2 = Array[i+1]; + v3 = Array[i+2]; + while (v2 != 0xDEAD) { + i += 3; + v1 = Array[i]; + v2 = Array[i+1]; + v3 = Array[i+1]; + } + } + } + } +} diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c new file mode 100644 index 000000000000..12071453be97 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c @@ -0,0 +1,188 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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 "odm_precomp.h" + +static bool CheckCondition(const u32 Condition, const u32 Hex) +{ + u32 _board = (Hex & 0x000000FF); + u32 _interface = (Hex & 0x0000FF00) >> 8; + u32 _platform = (Hex & 0x00FF0000) >> 16; + u32 cond = Condition; + + if (Condition == 0xCDCDCDCD) + return true; + + cond = Condition & 0x000000FF; + if ((_board == cond) && cond != 0x00) + return false; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ((_interface & cond) == 0 && cond != 0x07) + return false; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ((_platform & cond) == 0 && cond != 0x0F) + return false; + return true; +} + +/****************************************************************************** +* MAC_REG.TXT +******************************************************************************/ + +static u32 Array_MAC_REG_8723A[] = { + 0x420, 0x00000080, + 0x423, 0x00000000, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000006, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43A, 0x00000000, + 0x43B, 0x00000001, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000006, + 0x43F, 0x00000007, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000F0, + 0x446, 0x0000000F, + 0x447, 0x00000000, + 0x458, 0x00000041, + 0x459, 0x000000A8, + 0x45A, 0x00000072, + 0x45B, 0x000000B9, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x462, 0x00000008, + 0x463, 0x00000003, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x515, 0x00000010, + 0x516, 0x0000000A, + 0x517, 0x00000010, + 0x51A, 0x00000016, + 0x524, 0x0000000F, + 0x525, 0x0000004F, + 0x546, 0x00000040, + 0x547, 0x00000000, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55A, 0x00000002, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x652, 0x00000020, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, +}; + +void ODM_ReadAndConfig_MAC_REG_8723A(struct dm_odm_t *pDM_Odm) +{ + #define READ_NEXT_PAIR(v1, v2, i) \ + do { \ + i += 2; v1 = Array[i]; v2 = Array[i+1]; \ + } while (0) + + u32 hex = 0; + u32 i = 0; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_MAC_REG_8723A)/sizeof(u32); + u32 *Array = Array_MAC_REG_8723A; + + hex += board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 2) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + + /* This (offset, data) pair meets the condition. */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigMAC_8723A(pDM_Odm, v1, (u8)v2); + continue; + } else { + if (!CheckCondition(Array[i], hex)) { + /* Discard the following (offset, data) pairs. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2 */ + } else { + /* Configure matched pairs and skip to end of if-else. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) { + odm_ConfigMAC_8723A(pDM_Odm, v1, (u8)v2); + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } +} diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c new file mode 100644 index 000000000000..0f2ae05c8eae --- /dev/null +++ b/drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c @@ -0,0 +1,259 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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 "odm_precomp.h" + +static bool CheckCondition(const u32 Condition, const u32 Hex) +{ + u32 _board = (Hex & 0x000000FF); + u32 _interface = (Hex & 0x0000FF00) >> 8; + u32 _platform = (Hex & 0x00FF0000) >> 16; + u32 cond = Condition; + + if (Condition == 0xCDCDCDCD) + return true; + + cond = Condition & 0x000000FF; + if ((_board == cond) && cond != 0x00) + return false; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ((_interface & cond) == 0 && cond != 0x07) + return false; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ((_platform & cond) == 0 && cond != 0x0F) + return false; + return true; +} + +/****************************************************************************** +* RadioA_1T.TXT +******************************************************************************/ + +static u32 Array_RadioA_1T_8723A[] = { + 0x000, 0x00030159, + 0x001, 0x00031284, + 0x002, 0x00098000, + 0xFF0F011F, 0xABCD, + 0x003, 0x00018C63, + 0xCDCDCDCD, 0xCDCD, + 0x003, 0x00039C63, + 0xFF0F011F, 0xDEAD, + 0x004, 0x000210E7, + 0x009, 0x0002044F, + 0x00A, 0x0001A3F1, + 0x00B, 0x00014787, + 0x00C, 0x000896FE, + 0x00D, 0x0000E02C, + 0x00E, 0x00039CE7, + 0x00F, 0x00000451, + 0x019, 0x00000000, + 0x01A, 0x00030355, + 0x01B, 0x00060A00, + 0x01C, 0x000FC378, + 0x01D, 0x000A1250, + 0x01E, 0x0000024F, + 0x01F, 0x00000000, + 0x020, 0x0000B614, + 0x021, 0x0006C000, + 0x022, 0x00000000, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00000483, + 0x026, 0x0004F000, + 0x027, 0x000EC7D9, + 0x028, 0x00057730, + 0x029, 0x00004783, + 0x02A, 0x00000001, + 0x02B, 0x00021334, + 0x02A, 0x00000000, + 0x02B, 0x00000054, + 0x02A, 0x00000001, + 0x02B, 0x00000808, + 0x02B, 0x00053333, + 0x02C, 0x0000000C, + 0x02A, 0x00000002, + 0x02B, 0x00000808, + 0x02B, 0x0005B333, + 0x02C, 0x0000000D, + 0x02A, 0x00000003, + 0x02B, 0x00000808, + 0x02B, 0x00063333, + 0x02C, 0x0000000D, + 0x02A, 0x00000004, + 0x02B, 0x00000808, + 0x02B, 0x0006B333, + 0x02C, 0x0000000D, + 0x02A, 0x00000005, + 0x02B, 0x00000808, + 0x02B, 0x00073333, + 0x02C, 0x0000000D, + 0x02A, 0x00000006, + 0x02B, 0x00000709, + 0x02B, 0x0005B333, + 0x02C, 0x0000000D, + 0x02A, 0x00000007, + 0x02B, 0x00000709, + 0x02B, 0x00063333, + 0x02C, 0x0000000D, + 0x02A, 0x00000008, + 0x02B, 0x0000060A, + 0x02B, 0x0004B333, + 0x02C, 0x0000000D, + 0x02A, 0x00000009, + 0x02B, 0x0000060A, + 0x02B, 0x00053333, + 0x02C, 0x0000000D, + 0x02A, 0x0000000A, + 0x02B, 0x0000060A, + 0x02B, 0x0005B333, + 0x02C, 0x0000000D, + 0x02A, 0x0000000B, + 0x02B, 0x0000060A, + 0x02B, 0x00063333, + 0x02C, 0x0000000D, + 0x02A, 0x0000000C, + 0x02B, 0x0000060A, + 0x02B, 0x0006B333, + 0x02C, 0x0000000D, + 0x02A, 0x0000000D, + 0x02B, 0x0000060A, + 0x02B, 0x00073333, + 0x02C, 0x0000000D, + 0x02A, 0x0000000E, + 0x02B, 0x0000050B, + 0x02B, 0x00066666, + 0x02C, 0x0000001A, + 0x02A, 0x000E0000, + 0x010, 0x0004000F, + 0x011, 0x000E31FC, + 0x010, 0x0006000F, + 0x011, 0x000FF9F8, + 0x010, 0x0002000F, + 0x011, 0x000203F9, + 0x010, 0x0003000F, + 0x011, 0x000FF500, + 0x010, 0x00000000, + 0x011, 0x00000000, + 0x010, 0x0008000F, + 0x011, 0x0003F100, + 0x010, 0x0009000F, + 0x011, 0x00023100, + 0x012, 0x00032000, + 0x012, 0x00071000, + 0x012, 0x000B0000, + 0x012, 0x000FC000, + 0x013, 0x000287B3, + 0x013, 0x000244B7, + 0x013, 0x000204AB, + 0x013, 0x0001C49F, + 0x013, 0x00018493, + 0x013, 0x0001429B, + 0x013, 0x00010299, + 0x013, 0x0000C29C, + 0x013, 0x000081A0, + 0x013, 0x000040AC, + 0x013, 0x00000020, + 0x014, 0x0001944C, + 0x014, 0x00059444, + 0x014, 0x0009944C, + 0x014, 0x000D9444, + 0xFF0F011F, 0xABCD, + 0x015, 0x0000F424, + 0x015, 0x0004F424, + 0x015, 0x0008F424, + 0x015, 0x000CF424, + 0xCDCDCDCD, 0xCDCD, + 0x015, 0x0000F474, + 0x015, 0x0004F477, + 0x015, 0x0008F455, + 0x015, 0x000CF455, + 0xFF0F011F, 0xDEAD, + 0x016, 0x00000339, + 0x016, 0x00040339, + 0x016, 0x00080339, + 0xFF0F011F, 0xABCD, + 0x016, 0x000C0356, + 0xCDCDCDCD, 0xCDCD, + 0x016, 0x000C0366, + 0xFF0F011F, 0xDEAD, + 0x000, 0x00010159, + 0x018, 0x0000F401, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x01F, 0x00000003, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x01E, 0x00000247, + 0x01F, 0x00000000, + 0x000, 0x00030159, +}; + +void ODM_ReadAndConfig_RadioA_1T_8723A(struct dm_odm_t *pDM_Odm) +{ + #define READ_NEXT_PAIR(v1, v2, i) \ + do { \ + i += 2; v1 = Array[i]; v2 = Array[i+1];\ + } while (0) + + u32 hex = 0; + u32 i = 0; + u8 platform = 0x04; + u8 interfaceValue = pDM_Odm->SupportInterface; + u8 board = pDM_Odm->BoardType; + u32 ArrayLen = sizeof(Array_RadioA_1T_8723A)/sizeof(u32); + u32 *Array = Array_RadioA_1T_8723A; + + hex += board; + hex += interfaceValue << 8; + hex += platform << 16; + hex += 0xFF000000; + + for (i = 0; i < ArrayLen; i += 2) { + u32 v1 = Array[i]; + u32 v2 = Array[i+1]; + + /* This (offset, data) pair meets the condition. */ + if (v1 < 0xCDCDCDCD) { + odm_ConfigRF_RadioA_8723A(pDM_Odm, v1, v2); + continue; + } else { + if (!CheckCondition(Array[i], hex)) { + /* Discard the following (offset, data) pairs. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2 */ + } else { + /* Configure matched pairs and skip to end of if-else. */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen - 2) { + odm_ConfigRF_RadioA_8723A(pDM_Odm, v1, v2); + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } +} diff --git a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c new file mode 100644 index 000000000000..4f6b4b72f922 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/*++ +Copyright (c) Realtek Semiconductor Corp. All rights reserved. + +Module Name: + HalPwrSeqCmd.c + +Abstract: + Implement HW Power sequence configuration CMD handling routine for + Realtek devices. + +Major Change History: + When Who What + ---------- --------------- ------------------------------- + 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. + 2011-07-07 Roger Create. + +--*/ +#include + +/* */ +/* Description: */ +/* This routine deal with the Power Configuration CMDs parsing + for RTL8723/RTL8188E Series IC. */ +/* */ +/* Assumption: */ +/* We should follow specific format which was released from + HW SD. */ +/* */ +/* 2011.07.07, added by Roger. */ +/* */ +u8 HalPwrSeqCmdParsing23a(struct rtw_adapter *padapter, u8 CutVersion, + u8 FabVersion, u8 InterfaceType, + struct wlan_pwr_cfg PwrSeqCmd[]) +{ + struct wlan_pwr_cfg PwrCfgCmd = { 0 }; + u8 bPollingBit = false; + u32 AryIdx = 0; + u8 value = 0; + u32 offset = 0; + u32 pollingCount = 0; /* polling autoload done. */ + u32 maxPollingCnt = 5000; + + do { + PwrCfgCmd = PwrSeqCmd[AryIdx]; + + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: offset(%#x) cut_msk(%#x) " + "fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) " + "msk(%#x) value(%#x)\n", + GET_PWR_CFG_OFFSET(PwrCfgCmd), + GET_PWR_CFG_CUT_MASK(PwrCfgCmd), + GET_PWR_CFG_FAB_MASK(PwrCfgCmd), + GET_PWR_CFG_INTF_MASK(PwrCfgCmd), + GET_PWR_CFG_BASE(PwrCfgCmd), + GET_PWR_CFG_CMD(PwrCfgCmd), + GET_PWR_CFG_MASK(PwrCfgCmd), + GET_PWR_CFG_VALUE(PwrCfgCmd))); + + /* 2 Only Handle the command whose FAB, CUT, and Interface are + matched */ + if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && + (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && + (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) { + switch (GET_PWR_CFG_CMD(PwrCfgCmd)) { + case PWR_CMD_READ: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: " + "PWR_CMD_READ\n")); + break; + + case PWR_CMD_WRITE: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: " + "PWR_CMD_WRITE\n")); + offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); + + /* Read the value from system register */ + value = rtw_read8(padapter, offset); + + value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); + value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & + GET_PWR_CFG_MASK(PwrCfgCmd)); + + /* Write the value back to sytem register */ + rtw_write8(padapter, offset, value); + break; + + case PWR_CMD_POLLING: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: " + "PWR_CMD_POLLING\n")); + + bPollingBit = false; + offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); + do { + value = rtw_read8(padapter, offset); + + value &= GET_PWR_CFG_MASK(PwrCfgCmd); + if (value == + (GET_PWR_CFG_VALUE(PwrCfgCmd) & + GET_PWR_CFG_MASK(PwrCfgCmd))) + bPollingBit = true; + else + udelay(10); + + if (pollingCount++ > maxPollingCnt) { + DBG_8723A("Fail to polling " + "Offset[%#x]\n", + offset); + return false; + } + } while (!bPollingBit); + + break; + + case PWR_CMD_DELAY: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: " + "PWR_CMD_DELAY\n")); + if (GET_PWR_CFG_VALUE(PwrCfgCmd) == + PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd)); + else + udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd) * + 1000); + break; + + case PWR_CMD_END: + /* When this command is parsed, end + the process */ + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("HalPwrSeqCmdParsing23a: " + "PWR_CMD_END\n")); + return true; + break; + + default: + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("HalPwrSeqCmdParsing23a: " + "Unknown CMD!!\n")); + break; + } + } + + AryIdx++; /* Add Array Index */ + } while (1); + + return true; +} diff --git a/drivers/staging/rtl8723au/hal/hal_com.c b/drivers/staging/rtl8723au/hal/hal_com.c new file mode 100644 index 000000000000..0640f3522136 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/hal_com.c @@ -0,0 +1,881 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 +#include + +#include +#include +#include + +#define _HAL_INIT_C_ + +void dump_chip_info23a(struct hal_version ChipVersion) +{ + int cnt = 0; + u8 buf[128]; + + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723A_"); + + cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ? + "Normal_Chip" : "Test_Chip"); + cnt += sprintf((buf + cnt), "%s_", + IS_CHIP_VENDOR_TSMC(ChipVersion) ? "TSMC" : "UMC"); + if (IS_A_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "A_CUT_"); + else if (IS_B_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "B_CUT_"); + else if (IS_C_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "C_CUT_"); + else if (IS_D_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "D_CUT_"); + else if (IS_E_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "E_CUT_"); + else + cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", + ChipVersion.CUTVersion); + + if (IS_1T1R(ChipVersion)) + cnt += sprintf((buf + cnt), "1T1R_"); + else if (IS_1T2R(ChipVersion)) + cnt += sprintf((buf + cnt), "1T2R_"); + else if (IS_2T2R(ChipVersion)) + cnt += sprintf((buf + cnt), "2T2R_"); + else + cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_", + ChipVersion.RFType); + + cnt += sprintf((buf + cnt), "RomVer(%d)\n", ChipVersion.ROMVer); + + DBG_8723A("%s", buf); +} + +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +/* return the final channel plan decision */ +/* hw_channel_plan: channel plan from HW (efuse/eeprom) */ +/* sw_channel_plan: channel plan from SW (registry/module param) */ +/* def_channel_plan: channel plan used when the former two is invalid */ +u8 hal_com_get_channel_plan23a(struct rtw_adapter *padapter, u8 hw_channel_plan, + u8 sw_channel_plan, u8 def_channel_plan, + bool AutoLoadFail) +{ + u8 swConfig; + u8 chnlPlan; + + swConfig = true; + if (!AutoLoadFail) { + if (!rtw_is_channel_plan_valid(sw_channel_plan)) + swConfig = false; + if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) + swConfig = false; + } + + if (swConfig == true) + chnlPlan = sw_channel_plan; + else + chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); + + if (!rtw_is_channel_plan_valid(chnlPlan)) + chnlPlan = def_channel_plan; + + return chnlPlan; +} + +u8 MRateToHwRate23a(u8 rate) +{ + u8 ret = DESC_RATE1M; + + switch (rate) { + /* CCK and OFDM non-HT rates */ + case IEEE80211_CCK_RATE_1MB: + ret = DESC_RATE1M; + break; + case IEEE80211_CCK_RATE_2MB: + ret = DESC_RATE2M; + break; + case IEEE80211_CCK_RATE_5MB: + ret = DESC_RATE5_5M; + break; + case IEEE80211_CCK_RATE_11MB: + ret = DESC_RATE11M; + break; + case IEEE80211_OFDM_RATE_6MB: + ret = DESC_RATE6M; + break; + case IEEE80211_OFDM_RATE_9MB: + ret = DESC_RATE9M; + break; + case IEEE80211_OFDM_RATE_12MB: + ret = DESC_RATE12M; + break; + case IEEE80211_OFDM_RATE_18MB: + ret = DESC_RATE18M; + break; + case IEEE80211_OFDM_RATE_24MB: + ret = DESC_RATE24M; + break; + case IEEE80211_OFDM_RATE_36MB: + ret = DESC_RATE36M; + break; + case IEEE80211_OFDM_RATE_48MB: + ret = DESC_RATE48M; + break; + case IEEE80211_OFDM_RATE_54MB: + ret = DESC_RATE54M; + break; + + /* HT rates since here */ + /* case MGN_MCS0: ret = DESC_RATEMCS0; break; */ + /* case MGN_MCS1: ret = DESC_RATEMCS1; break; */ + /* case MGN_MCS2: ret = DESC_RATEMCS2; break; */ + /* case MGN_MCS3: ret = DESC_RATEMCS3; break; */ + /* case MGN_MCS4: ret = DESC_RATEMCS4; break; */ + /* case MGN_MCS5: ret = DESC_RATEMCS5; break; */ + /* case MGN_MCS6: ret = DESC_RATEMCS6; break; */ + /* case MGN_MCS7: ret = DESC_RATEMCS7; break; */ + + default: + break; + } + return ret; +} + +void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 i, is_brate, brate; + u16 brate_cfg = 0; + u8 rate_index; + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK; + brate = mBratesOS[i] & 0x7f; + + if (is_brate) { + switch (brate) { + case IEEE80211_CCK_RATE_1MB: + brate_cfg |= RATE_1M; + break; + case IEEE80211_CCK_RATE_2MB: + brate_cfg |= RATE_2M; + break; + case IEEE80211_CCK_RATE_5MB: + brate_cfg |= RATE_5_5M; + break; + case IEEE80211_CCK_RATE_11MB: + brate_cfg |= RATE_11M; + break; + case IEEE80211_OFDM_RATE_6MB: + brate_cfg |= RATE_6M; + break; + case IEEE80211_OFDM_RATE_9MB: + brate_cfg |= RATE_9M; + break; + case IEEE80211_OFDM_RATE_12MB: + brate_cfg |= RATE_12M; + break; + case IEEE80211_OFDM_RATE_18MB: + brate_cfg |= RATE_18M; + break; + case IEEE80211_OFDM_RATE_24MB: + brate_cfg |= RATE_24M; + break; + case IEEE80211_OFDM_RATE_36MB: + brate_cfg |= RATE_36M; + break; + case IEEE80211_OFDM_RATE_48MB: + brate_cfg |= RATE_48M; + break; + case IEEE80211_OFDM_RATE_54MB: + brate_cfg |= RATE_54M; + break; + } + } + } + + /* 2007.01.16, by Emily */ + /* Select RRSR (in Legacy-OFDM and CCK) */ + /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, + and 1M from the Basic rate. */ + /* We do not use other rates. */ + /* 2011.03.30 add by Luke Lee */ + /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */ + /* because CCK 2M has poor TXEVM */ + /* CCK 5.5M & 11M ACK should be enabled for better + performance */ + + brate_cfg = (brate_cfg | 0xd) & 0x15d; + pHalData->BasicRateSet = brate_cfg; + brate_cfg |= 0x01; /* default enable 1M ACK rate */ + DBG_8723A("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", brate_cfg); + + /* Set RRSR rate table. */ + rtw_write8(padapter, REG_RRSR, brate_cfg & 0xff); + rtw_write8(padapter, REG_RRSR + 1, (brate_cfg >> 8) & 0xff); + rtw_write8(padapter, REG_RRSR + 2, + rtw_read8(padapter, REG_RRSR + 2) & 0xf0); + + rate_index = 0; + /* Set RTS initial rate */ + while (brate_cfg > 0x1) { + brate_cfg = (brate_cfg >> 1); + rate_index++; + } + /* Ziv - Check */ + rtw_write8(padapter, REG_INIRTS_RATE_SEL, rate_index); + + return; +} + +static void _OneOutPipeMapping(struct rtw_adapter *pAdapter) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0]; /* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0]; /* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD */ +} + +static void _TwoOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + if (bWIFICfg) { /* WMM */ + /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ + /* 0, 1, 0, 1, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:L */ + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1]; /* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0]; /* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/ + } else { /* typical setting */ + /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ + /* 1, 1, 0, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:L */ + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/ + } +} + +static void _ThreeOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + if (bWIFICfg) { /* for WMM */ + /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ + /* 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L */ + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/ + } else { /* typical setting */ + /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ + /* 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L */ + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2]; /* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/ + } +} + +bool Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe) +{ + struct registry_priv *pregistrypriv = &pAdapter->registrypriv; + bool bWIFICfg = (pregistrypriv->wifi_spec) ? true : false; + bool result = true; + + switch (NumOutPipe) { + case 2: + _TwoOutPipeMapping(pAdapter, bWIFICfg); + break; + case 3: + _ThreeOutPipeMapping(pAdapter, bWIFICfg); + break; + case 1: + _OneOutPipeMapping(pAdapter); + break; + default: + result = false; + break; + } + + return result; +} + +void hal_init_macaddr23a(struct rtw_adapter *adapter) +{ + rtw_hal_set_hwreg23a(adapter, HW_VAR_MAC_ADDR, + adapter->eeprompriv.mac_addr); +} + +/* +* C2H event format: +* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID +* BITS [127:120] [119:16] [15:8] [7:4] [3:0] +*/ + +void c2h_evt_clear23a(struct rtw_adapter *adapter) +{ + rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); +} + +s32 c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf) +{ + s32 ret = _FAIL; + struct c2h_evt_hdr *c2h_evt; + int i; + u8 trigger; + + if (buf == NULL) + goto exit; + + trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); + + if (trigger == C2H_EVT_HOST_CLOSE) + goto exit; /* Not ready */ + else if (trigger != C2H_EVT_FW_CLOSE) + goto clear_evt; /* Not a valid value */ + + c2h_evt = (struct c2h_evt_hdr *)buf; + + memset(c2h_evt, 0, 16); + + *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); + *(buf + 1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1); + + RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read23a(): ", + &c2h_evt, sizeof(c2h_evt)); + + if (0) { + DBG_8723A("%s id:%u, len:%u, seq:%u, trigger:0x%02x\n", + __func__, c2h_evt->id, c2h_evt->plen, c2h_evt->seq, + trigger); + } + + /* Read the content */ + for (i = 0; i < c2h_evt->plen; i++) + c2h_evt->payload[i] = rtw_read8(adapter, + REG_C2HEVT_MSG_NORMAL + + sizeof(*c2h_evt) + i); + + RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, + "c2h_evt_read23a(): Command Content:\n", c2h_evt->payload, + c2h_evt->plen); + + ret = _SUCCESS; + +clear_evt: + /* + * Clear event to notify FW we have read the command. + * If this field isn't clear, the FW won't update the + * next command message. + */ + c2h_evt_clear23a(adapter); +exit: + return ret; +} + +void +rtl8723a_set_ampdu_min_space(struct rtw_adapter *padapter, u8 MinSpacingToSet) +{ + u8 SecMinSpace; + + if (MinSpacingToSet <= 7) { + switch (padapter->securitypriv.dot11PrivacyAlgrthm) { + case _NO_PRIVACY_: + case _AES_: + SecMinSpace = 0; + break; + + case _WEP40_: + case _WEP104_: + case _TKIP_: + case _TKIP_WTMIC_: + SecMinSpace = 6; + break; + default: + SecMinSpace = 7; + break; + } + + if (MinSpacingToSet < SecMinSpace) + MinSpacingToSet = SecMinSpace; + + /* RT_TRACE(COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + padapter->MgntInfo.MinSpaceCfg)); */ + MinSpacingToSet |= + rtw_read8(padapter, REG_AMPDU_MIN_SPACE) & 0xf8; + rtw_write8(padapter, REG_AMPDU_MIN_SPACE, + MinSpacingToSet); + } +} + +void rtl8723a_set_ampdu_factor(struct rtw_adapter *padapter, u8 FactorToSet) +{ + u8 RegToSet_Normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + u8 MaxAggNum; + u8 *pRegToSet; + u8 index = 0; + + pRegToSet = RegToSet_Normal; /* 0xb972a841; */ +#ifdef CONFIG_8723AU_BT_COEXIST + if ((BT_IsBtDisabled(padapter) == false) && + (BT_1Ant(padapter) == true)) { + MaxAggNum = 0x8; + } else +#endif /* CONFIG_8723AU_BT_COEXIST */ + { + MaxAggNum = 0xF; + } + + if (FactorToSet <= 3) { + FactorToSet = (1 << (FactorToSet + 2)); + if (FactorToSet > MaxAggNum) + FactorToSet = MaxAggNum; + + for (index = 0; index < 4; index++) { + if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4)) + pRegToSet[index] = (pRegToSet[index] & 0x0f) | + (FactorToSet << 4); + + if ((pRegToSet[index] & 0x0f) > FactorToSet) + pRegToSet[index] = (pRegToSet[index] & 0xf0) | + FactorToSet; + + rtw_write8(padapter, REG_AGGLEN_LMT + index, + pRegToSet[index]); + } + + /* RT_TRACE(COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_FACTOR: %#x\n", FactorToSet)); */ + } +} + +void rtl8723a_set_acm_ctrl(struct rtw_adapter *padapter, u8 ctrl) +{ + u8 hwctrl = 0; + + if (ctrl != 0) { + hwctrl |= AcmHw_HwEn; + + if (ctrl & BIT(1)) /* BE */ + hwctrl |= AcmHw_BeqEn; + + if (ctrl & BIT(2)) /* VI */ + hwctrl |= AcmHw_ViqEn; + + if (ctrl & BIT(3)) /* VO */ + hwctrl |= AcmHw_VoqEn; + } + + DBG_8723A("[HW_VAR_ACM_CTRL] Write 0x%02X\n", hwctrl); + rtw_write8(padapter, REG_ACMHWCTRL, hwctrl); +} + +void rtl8723a_set_media_status(struct rtw_adapter *padapter, u8 status) +{ + u8 val8; + + val8 = rtw_read8(padapter, MSR) & 0x0c; + val8 |= status; + rtw_write8(padapter, MSR, val8); +} + +void rtl8723a_set_media_status1(struct rtw_adapter *padapter, u8 status) +{ + u8 val8; + + val8 = rtw_read8(padapter, MSR) & 0x03; + val8 |= status << 2; + rtw_write8(padapter, MSR, val8); +} + +void rtl8723a_set_bcn_func(struct rtw_adapter *padapter, u8 val) +{ + if (val) + SetBcnCtrlReg23a(padapter, EN_BCN_FUNCTION | EN_TXBCN_RPT, 0); + else + SetBcnCtrlReg23a(padapter, 0, EN_BCN_FUNCTION | EN_TXBCN_RPT); +} + +void rtl8723a_check_bssid(struct rtw_adapter *padapter, u8 val) +{ + u32 val32; + val32 = rtw_read32(padapter, REG_RCR); + if (val) + val32 |= RCR_CBSSID_DATA | RCR_CBSSID_BCN; + else + val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtw_write32(padapter, REG_RCR, val32); +} + +void rtl8723a_mlme_sitesurvey(struct rtw_adapter *padapter, u8 flag) +{ + if (flag) { /* under sitesurvey */ + u32 v32; + + /* config RCR to receive different BSSID & not + to receive data frame */ + v32 = rtw_read32(padapter, REG_RCR); + v32 &= ~(RCR_CBSSID_BCN); + rtw_write32(padapter, REG_RCR, v32); + /* reject all data frame */ + rtw_write16(padapter, REG_RXFLTMAP2, 0); + + /* disable update TSF */ + SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0); + } else { /* sitesurvey done */ + + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo; + u32 v32; + + pmlmeinfo = &pmlmeext->mlmext_info; + + if ((is_client_associated_to_ap23a(padapter) == true) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + /* enable to rx data frame */ + rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); + + /* enable update TSF */ + SetBcnCtrlReg23a(padapter, 0, DIS_TSF_UDT); + } + + v32 = rtw_read32(padapter, REG_RCR); + v32 |= RCR_CBSSID_BCN; + rtw_write32(padapter, REG_RCR, v32); + } + +#ifdef CONFIG_8723AU_BT_COEXIST + BT_WifiScanNotify(padapter, flag ? true : false); +#endif +} + +void rtl8723a_on_rcr_am(struct rtw_adapter *padapter) +{ + rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR) | RCR_AM); + DBG_8723A("%s, %d, RCR = %x \n", __FUNCTION__, __LINE__, + rtw_read32(padapter, REG_RCR)); +} + +void rtl8723a_off_rcr_am(struct rtw_adapter *padapter) +{ + rtw_write32(padapter, REG_RCR, + rtw_read32(padapter, REG_RCR) & (~RCR_AM)); + DBG_8723A("%s, %d, RCR = %x \n", __FUNCTION__, __LINE__, + rtw_read32(padapter, REG_RCR)); +} + +void rtl8723a_set_slot_time(struct rtw_adapter *padapter, u8 slottime) +{ + u8 u1bAIFS, aSifsTime; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + rtw_write8(padapter, REG_SLOT, slottime); + + if (pmlmeinfo->WMM_enable == 0) { + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + + u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); + + /* Temporary removed, 2008.06.20. */ + rtw_write8(padapter, REG_EDCA_VO_PARAM, u1bAIFS); + rtw_write8(padapter, REG_EDCA_VI_PARAM, u1bAIFS); + rtw_write8(padapter, REG_EDCA_BE_PARAM, u1bAIFS); + rtw_write8(padapter, REG_EDCA_BK_PARAM, u1bAIFS); + } +} + +void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 regTmp; + + /* Joseph marked out for Netgear 3500 TKIP + channel 7 issue.(Temporarily) */ + regTmp = (pHalData->nCur40MhzPrimeSC) << 5; + /* regTmp = 0; */ + if (bShortPreamble) + regTmp |= 0x80; + rtw_write8(padapter, REG_RRSR + 2, regTmp); +} + +void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec) +{ + rtw_write8(padapter, REG_SECCFG, sec); +} + +void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex) +{ + u8 i; + u32 ulCommand = 0; + u32 ulContent = 0; + u32 ulEncAlgo = CAM_AES; + + for (i = 0; i < CAM_CONTENT_COUNT; i++) { + /* filled id in CAM config 2 byte */ + if (i == 0) { + ulContent |= (ucIndex & 0x03) | + ((u16) (ulEncAlgo) << 2); + /* ulContent |= CAM_VALID; */ + } else { + ulContent = 0; + } + /* polling bit, and No Write enable, and address */ + ulCommand = CAM_CONTENT_COUNT * ucIndex + i; + ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE; + /* write content 0 is equall to mark invalid */ + /* delay_ms(40); */ + rtw_write32(padapter, WCAMI, ulContent); + /* RT_TRACE(COMP_SEC, DBG_LOUD, + ("CAM_empty_entry23a(): WRITE A4: %lx \n", ulContent));*/ + /* delay_ms(40); */ + rtw_write32(padapter, RWCAM, ulCommand); + /* RT_TRACE(COMP_SEC, DBG_LOUD, + ("CAM_empty_entry23a(): WRITE A0: %lx \n", ulCommand));*/ + } +} + +void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter) +{ + rtw_write32(padapter, RWCAM, BIT(31) | BIT(30)); +} + +void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2) +{ + u32 cmd; + + rtw_write32(padapter, WCAMI, val1); + + cmd = CAM_POLLINIG | CAM_WRITE | val2; + rtw_write32(padapter, RWCAM, cmd); +} + +void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter) +{ +#define RW_RELEASE_EN BIT(18) +#define RXDMA_IDLE BIT(17) + + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + u8 trycnt = 100; + + /* pause tx */ + rtw_write8(padapter, REG_TXPAUSE, 0xff); + + /* keep sn */ + padapter->xmitpriv.nqos_ssn = rtw_read16(padapter, REG_NQOS_SEQ); + + if (pwrpriv->bkeepfwalive != true) { + u32 v32; + + /* RX DMA stop */ + v32 = rtw_read32(padapter, REG_RXPKT_NUM); + v32 |= RW_RELEASE_EN; + rtw_write32(padapter, REG_RXPKT_NUM, v32); + do { + v32 = rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE; + if (!v32) + break; + } while (trycnt--); + if (trycnt == 0) { + DBG_8723A("Stop RX DMA failed......\n"); + } + + /* RQPN Load 0 */ + rtw_write16(padapter, REG_RQPN_NPQ, 0); + rtw_write32(padapter, REG_RQPN, 0x80000000); + mdelay(10); + } +} + +void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->bMacPwrCtrlOn = val; + DBG_8723A("%s: bMacPwrCtrlOn =%d\n", __func__, pHalData->bMacPwrCtrlOn); +} + +void rtl8723a_bcn_valid(struct rtw_adapter *padapter) +{ + /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, + write 1 to clear, Clear by sw */ + rtw_write8(padapter, REG_TDECTRL + 2, + rtw_read8(padapter, REG_TDECTRL + 2) | BIT0); +} + +void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause) +{ + rtw_write8(padapter, REG_TXPAUSE, pause); +} + +void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval) +{ + rtw_write16(padapter, REG_BCN_INTERVAL, interval); +} + +void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter, + u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2) +{ + /* SIFS_Timer = 0x0a0a0808; */ + /* RESP_SIFS for CCK */ + /* SIFS_T2T_CCK (0x08) */ + rtw_write8(padapter, REG_R2T_SIFS, r2t1); + /* SIFS_R2T_CCK(0x08) */ + rtw_write8(padapter, REG_R2T_SIFS + 1, r2t2); + /* RESP_SIFS for OFDM */ + /* SIFS_T2T_OFDM (0x0a) */ + rtw_write8(padapter, REG_T2T_SIFS, t2t1); + /* SIFS_R2T_OFDM(0x0a) */ + rtw_write8(padapter, REG_T2T_SIFS + 1, t2t2); +} + +void rtl8723a_set_ac_param_vo(struct rtw_adapter *padapter, u32 vo) +{ + rtw_write32(padapter, REG_EDCA_VO_PARAM, vo); +} + +void rtl8723a_set_ac_param_vi(struct rtw_adapter *padapter, u32 vi) +{ + rtw_write32(padapter, REG_EDCA_VI_PARAM, vi); +} + +void rtl8723a_set_ac_param_be(struct rtw_adapter *padapter, u32 be) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->AcParam_BE = be; + rtw_write32(padapter, REG_EDCA_BE_PARAM, be); +} + +void rtl8723a_set_ac_param_bk(struct rtw_adapter *padapter, u32 bk) +{ + rtw_write32(padapter, REG_EDCA_BK_PARAM, bk); +} + +void rtl8723a_set_rxdma_agg_pg_th(struct rtw_adapter *padapter, u8 val) +{ + rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, val); +} + +void rtl8723a_set_nav_upper(struct rtw_adapter *padapter, u32 usNavUpper) +{ + if (usNavUpper > HAL_8723A_NAV_UPPER_UNIT * 0xFF) { + RT_TRACE(_module_hal_init_c_, _drv_notice_, + ("The setting value (0x%08X us) of NAV_UPPER " + "is larger than (%d * 0xFF)!!!\n", + usNavUpper, HAL_8723A_NAV_UPPER_UNIT)); + return; + } + + /* The value of ((usNavUpper + HAL_8723A_NAV_UPPER_UNIT - 1) / + HAL_8723A_NAV_UPPER_UNIT) */ + /* is getting the upper integer. */ + usNavUpper = (usNavUpper + HAL_8723A_NAV_UPPER_UNIT - 1) / + HAL_8723A_NAV_UPPER_UNIT; + rtw_write8(padapter, REG_NAV_UPPER, (u8) usNavUpper); +} + +void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dig_t *pDigTable = &pHalData->odmpriv.DM_DigTable; + + if (rx_gain == 0xff) /* restore rx gain */ + ODM_Write_DIG23a(&pHalData->odmpriv, pDigTable->BackupIGValue); + else { + pDigTable->BackupIGValue = pDigTable->CurIGValue; + ODM_Write_DIG23a(&pHalData->odmpriv, rx_gain); + } +} + +void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->odmpriv.SupportAbility = val; +} + +void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (val) /* save dm flag */ + pHalData->odmpriv.BK_SupportAbility = + pHalData->odmpriv.SupportAbility; + else /* restore dm flag */ + pHalData->odmpriv.SupportAbility = + pHalData->odmpriv.BK_SupportAbility; +} + +void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (val == DYNAMIC_ALL_FUNC_ENABLE) { + pHalData->dmpriv.DMFlag = pHalData->dmpriv.InitDMFlag; + pHalData->odmpriv.SupportAbility = pHalData->dmpriv.InitODMFlag; + } else { + pHalData->odmpriv.SupportAbility |= val; + } +} + +void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->odmpriv.SupportAbility &= val; +} + +void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val) +{ + rtw_write8(padapter, REG_USB_HRPWM, val); +} diff --git a/drivers/staging/rtl8723au/hal/hal_intf.c b/drivers/staging/rtl8723au/hal/hal_intf.c new file mode 100644 index 000000000000..c1a5b735ecf3 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/hal_intf.c @@ -0,0 +1,418 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#define _HAL_INTF_C_ +#include +#include + +#include + +#include + +void rtw_hal_chip_configure23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.intf_chip_configure) + padapter->HalFunc.intf_chip_configure(padapter); +} + +void rtw_hal_read_chip_info23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.read_adapter_info) + padapter->HalFunc.read_adapter_info(padapter); +} + +void rtw_hal_read_chip_version23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.read_chip_version) + padapter->HalFunc.read_chip_version(padapter); +} + +void rtw_hal_def_value_init23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.init_default_value) + padapter->HalFunc.init_default_value(padapter); +} +void rtw_hal_free_data23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.free_hal_data) + padapter->HalFunc.free_hal_data(padapter); +} +void rtw_hal_dm_init23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.dm_init) + padapter->HalFunc.dm_init(padapter); +} +void rtw_hal_dm_deinit23a(struct rtw_adapter *padapter) +{ + /* cancel dm timer */ + if (padapter->HalFunc.dm_deinit) + padapter->HalFunc.dm_deinit(padapter); +} +void rtw_hal_sw_led_init23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.InitSwLeds) + padapter->HalFunc.InitSwLeds(padapter); +} + +void rtw_hal_sw_led_deinit23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.DeInitSwLeds) + padapter->HalFunc.DeInitSwLeds(padapter); +} + +u32 rtw_hal_power_on23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.hal_power_on) + return padapter->HalFunc.hal_power_on(padapter); + return _FAIL; +} + +uint rtw_hal_init23a(struct rtw_adapter *padapter) +{ + uint status = _SUCCESS; + + padapter->hw_init_completed = false; + + status = padapter->HalFunc.hal_init(padapter); + + if (status == _SUCCESS) { + padapter->hw_init_completed = true; + + if (padapter->registrypriv.notch_filter == 1) + rtw_hal_notch_filter23a(padapter, 1); + + rtw_hal_reset_security_engine23a(padapter); + } else { + padapter->hw_init_completed = false; + DBG_8723A("rtw_hal_init23a: hal__init fail\n"); + } + + RT_TRACE(_module_hal_init_c_, _drv_err_, ("-rtl871x_hal_init:status = 0x%x\n", status)); + + return status; +} + +uint rtw_hal_deinit23a(struct rtw_adapter *padapter) +{ + uint status = _SUCCESS; + + status = padapter->HalFunc.hal_deinit(padapter); + + if (status == _SUCCESS) + padapter->hw_init_completed = false; + else + DBG_8723A("\n rtw_hal_deinit23a: hal_init fail\n"); + return status; +} + +void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val) +{ + if (padapter->HalFunc.SetHwRegHandler) + padapter->HalFunc.SetHwRegHandler(padapter, variable, val); +} + +void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val) +{ + if (padapter->HalFunc.GetHwRegHandler) + padapter->HalFunc.GetHwRegHandler(padapter, variable, val); +} + +u8 rtw_hal_set_def_var23a(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue) +{ + if (padapter->HalFunc.SetHalDefVarHandler) + return padapter->HalFunc.SetHalDefVarHandler(padapter, eVariable, pValue); + return _FAIL; +} +u8 rtw_hal_get_def_var23a(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue) +{ + if (padapter->HalFunc.GetHalDefVarHandler) + return padapter->HalFunc.GetHalDefVarHandler(padapter, eVariable, pValue); + return _FAIL; +} + +void rtw_hal_set_odm_var23a(struct rtw_adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) +{ + if (padapter->HalFunc.SetHalODMVarHandler) + padapter->HalFunc.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet); +} +void rtw_hal_get_odm_var23a(struct rtw_adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) +{ + if (padapter->HalFunc.GetHalODMVarHandler) + padapter->HalFunc.GetHalODMVarHandler(padapter, eVariable, pValue1, bSet); +} + +void rtw_hal_enable_interrupt23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.enable_interrupt) + padapter->HalFunc.enable_interrupt(padapter); + else + DBG_8723A("%s: HalFunc.enable_interrupt is NULL!\n", __FUNCTION__); + +} +void rtw_hal_disable_interrupt23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.disable_interrupt) + padapter->HalFunc.disable_interrupt(padapter); + else + DBG_8723A("%s: HalFunc.disable_interrupt is NULL!\n", __FUNCTION__); + +} + +u32 rtw_hal_inirp_init23a(struct rtw_adapter *padapter) +{ + u32 rst = _FAIL; + if (padapter->HalFunc.inirp_init) + rst = padapter->HalFunc.inirp_init(padapter); + else + DBG_8723A(" %s HalFunc.inirp_init is NULL!!!\n", __FUNCTION__); + return rst; +} + +u32 rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter) +{ + + if (padapter->HalFunc.inirp_deinit) + return padapter->HalFunc.inirp_deinit(padapter); + + return _FAIL; + +} + +u8 rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val) +{ + if (padapter->HalFunc.interface_ps_func) + return padapter->HalFunc.interface_ps_func(padapter, efunc_id, val); + return _FAIL; +} + +s32 rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + if (padapter->HalFunc.hal_xmitframe_enqueue) + return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); + + return false; +} + +s32 rtw_hal_xmit23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + if (padapter->HalFunc.hal_xmit) + return padapter->HalFunc.hal_xmit(padapter, pxmitframe); + + return false; +} + +s32 rtw_hal_mgnt_xmit23a(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe) +{ + s32 ret = _FAIL; + if (padapter->HalFunc.mgnt_xmit) + ret = padapter->HalFunc.mgnt_xmit(padapter, pmgntframe); + return ret; +} + +s32 rtw_hal_init23a_xmit_priv(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.init_xmit_priv != NULL) + return padapter->HalFunc.init_xmit_priv(padapter); + return _FAIL; +} +void rtw_hal_free_xmit_priv23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.free_xmit_priv != NULL) + padapter->HalFunc.free_xmit_priv(padapter); +} + +s32 rtw_hal_init23a_recv_priv(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.init_recv_priv) + return padapter->HalFunc.init_recv_priv(padapter); + + return _FAIL; +} +void rtw_hal_free_recv_priv23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.free_recv_priv) + padapter->HalFunc.free_recv_priv(padapter); +} + +void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level) +{ + struct rtw_adapter *padapter; + struct mlme_priv *pmlmepriv; + + if (!psta) + return; + + padapter = psta->padapter; + + pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + add_RATid23a(padapter, psta, rssi_level); + } else { + if (padapter->HalFunc.UpdateRAMaskHandler) + padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level); + } +} + +void rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level) +{ + if (padapter->HalFunc.Add_RateATid) + padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level); +} + +/* Start specifical interface thread */ +void rtw_hal_start_thread23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.run_thread) + padapter->HalFunc.run_thread(padapter); +} +/* Start specifical interface thread */ +void rtw_hal_stop_thread23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.cancel_thread) + padapter->HalFunc.cancel_thread(padapter); +} + +u32 rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask) +{ + u32 data = 0; + if (padapter->HalFunc.read_bbreg) + data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask); + return data; +} +void rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) +{ + if (padapter->HalFunc.write_bbreg) + padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data); +} + +u32 rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) +{ + u32 data = 0; + if (padapter->HalFunc.read_rfreg) + data = padapter->HalFunc.read_rfreg(padapter, eRFPath, RegAddr, BitMask); + return data; +} +void rtw_hal_write_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + if (padapter->HalFunc.write_rfreg) + padapter->HalFunc.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data); +} + +s32 rtw_hal_interrupt_handler23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.interrupt_handler) + return padapter->HalFunc.interrupt_handler(padapter); + return _FAIL; +} + +void rtw_hal_set_bwmode23a(struct rtw_adapter *padapter, + enum ht_channel_width Bandwidth, u8 offset) +{ + if (padapter->HalFunc.set_bwmode_handler) + padapter->HalFunc.set_bwmode_handler(padapter, Bandwidth, + offset); +} + +void rtw_hal_set_chan23a(struct rtw_adapter *padapter, u8 channel) +{ + if (padapter->HalFunc.set_channel_handler) + padapter->HalFunc.set_channel_handler(padapter, channel); +} + +void rtw_hal_dm_watchdog23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.hal_dm_watchdog) + padapter->HalFunc.hal_dm_watchdog(padapter); +} + +void rtw_hal_bcn_related_reg_setting23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.SetBeaconRelatedRegistersHandler) + padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter); +} + +void rtw_hal_sreset_init23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.sreset_init_value23a) + padapter->HalFunc.sreset_init_value23a(padapter); +} +void rtw_hal_sreset_reset23a(struct rtw_adapter *padapter) +{ + padapter = GET_PRIMARY_ADAPTER(padapter); + + if (padapter->HalFunc.silentreset) + padapter->HalFunc.silentreset(padapter); +} + +void rtw_hal_sreset_reset23a_value23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.sreset_reset_value23a) + padapter->HalFunc.sreset_reset_value23a(padapter); +} + +void rtw_hal_sreset_xmit_status_check23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.sreset_xmit_status_check) + padapter->HalFunc.sreset_xmit_status_check(padapter); +} +void rtw_hal_sreset_linked_status_check23a(struct rtw_adapter *padapter) +{ + if (padapter->HalFunc.sreset_linked_status_check) + padapter->HalFunc.sreset_linked_status_check(padapter); +} +u8 rtw_hal_sreset_get_wifi_status23a(struct rtw_adapter *padapter) +{ + u8 status = 0; + if (padapter->HalFunc.sreset_get_wifi_status23a) + status = padapter->HalFunc.sreset_get_wifi_status23a(padapter); + return status; +} + +bool rtw_hal_sreset_inprogress(struct rtw_adapter *padapter) +{ + bool inprogress = false; + + padapter = GET_PRIMARY_ADAPTER(padapter); + + if (padapter->HalFunc.sreset_inprogress) + inprogress = padapter->HalFunc.sreset_inprogress(padapter); + return inprogress; +} + +void rtw_hal_notch_filter23a(struct rtw_adapter *adapter, bool enable) +{ + if (adapter->HalFunc.hal_notch_filter) + adapter->HalFunc.hal_notch_filter(adapter, enable); +} + +void rtw_hal_reset_security_engine23a(struct rtw_adapter *adapter) +{ + if (adapter->HalFunc.hal_reset_security_engine) + adapter->HalFunc.hal_reset_security_engine(adapter); +} + +s32 rtw_hal_c2h_handler23a(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt) +{ + s32 ret = _FAIL; + if (adapter->HalFunc.c2h_handler) + ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); + return ret; +} + +c2h_id_filter rtw_hal_c2h_id_filter_ccx23a(struct rtw_adapter *adapter) +{ + return adapter->HalFunc.c2h_id_filter_ccx; +} diff --git a/drivers/staging/rtl8723au/hal/odm.c b/drivers/staging/rtl8723au/hal/odm.c new file mode 100644 index 000000000000..584a74ed2943 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/odm.c @@ -0,0 +1,2090 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 "odm_precomp.h" + +static const u16 dB_Invert_Table[8][12] = { + {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4}, + {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16}, + {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63}, + {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251}, + {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000}, + {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, + {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849}, + {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535} +}; + +static u32 EDCAParam[HT_IOT_PEER_MAX][3] = { /* UL DL */ + {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */ + {0xa44f, 0x5ea44f, 0x5e431c}, /* 1:realtek AP */ + {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 2:unknown AP => realtek_92SE */ + {0x5ea32b, 0x5ea42b, 0x5e4322}, /* 3:broadcom AP */ + {0x5ea422, 0x00a44f, 0x00a44f}, /* 4:ralink AP */ + {0x5ea322, 0x00a630, 0x00a44f}, /* 5:atheros AP */ + {0x5e4322, 0x5e4322, 0x5e4322},/* 6:cisco AP */ + {0x5ea44f, 0x00a44f, 0x5ea42b}, /* 8:marvell AP */ + {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 10:unknown AP => 92U AP */ + {0x5ea42b, 0xa630, 0x5e431c}, /* 11:airgocap AP */ +}; + +/* EDCA Paramter for AP/ADSL by Mingzhi 2011-11-22 */ + +/* Global var */ +u32 OFDMSwingTable23A[OFDM_TABLE_SIZE_92D] = { + 0x7f8001fe, /* 0, +6.0dB */ + 0x788001e2, /* 1, +5.5dB */ + 0x71c001c7, /* 2, +5.0dB */ + 0x6b8001ae, /* 3, +4.5dB */ + 0x65400195, /* 4, +4.0dB */ + 0x5fc0017f, /* 5, +3.5dB */ + 0x5a400169, /* 6, +3.0dB */ + 0x55400155, /* 7, +2.5dB */ + 0x50800142, /* 8, +2.0dB */ + 0x4c000130, /* 9, +1.5dB */ + 0x47c0011f, /* 10, +1.0dB */ + 0x43c0010f, /* 11, +0.5dB */ + 0x40000100, /* 12, +0dB */ + 0x3c8000f2, /* 13, -0.5dB */ + 0x390000e4, /* 14, -1.0dB */ + 0x35c000d7, /* 15, -1.5dB */ + 0x32c000cb, /* 16, -2.0dB */ + 0x300000c0, /* 17, -2.5dB */ + 0x2d4000b5, /* 18, -3.0dB */ + 0x2ac000ab, /* 19, -3.5dB */ + 0x288000a2, /* 20, -4.0dB */ + 0x26000098, /* 21, -4.5dB */ + 0x24000090, /* 22, -5.0dB */ + 0x22000088, /* 23, -5.5dB */ + 0x20000080, /* 24, -6.0dB */ + 0x1e400079, /* 25, -6.5dB */ + 0x1c800072, /* 26, -7.0dB */ + 0x1b00006c, /* 27. -7.5dB */ + 0x19800066, /* 28, -8.0dB */ + 0x18000060, /* 29, -8.5dB */ + 0x16c0005b, /* 30, -9.0dB */ + 0x15800056, /* 31, -9.5dB */ + 0x14400051, /* 32, -10.0dB */ + 0x1300004c, /* 33, -10.5dB */ + 0x12000048, /* 34, -11.0dB */ + 0x11000044, /* 35, -11.5dB */ + 0x10000040, /* 36, -12.0dB */ + 0x0f00003c,/* 37, -12.5dB */ + 0x0e400039,/* 38, -13.0dB */ + 0x0d800036,/* 39, -13.5dB */ + 0x0cc00033,/* 40, -14.0dB */ + 0x0c000030,/* 41, -14.5dB */ + 0x0b40002d,/* 42, -15.0dB */ +}; + +u8 CCKSwingTable_Ch1_Ch1323A[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */ + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ +}; + +u8 CCKSwingTable_Ch1423A[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */ + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ +}; + +/* Local Function predefine. */ + +/* START------------COMMON INFO RELATED--------------- */ +void odm_CommonInfoSelfInit23a(struct dm_odm_t *pDM_Odm); + +void odm_CommonInfoSelfUpdate23a(struct dm_odm_t *pDM_Odm); + +void odm_CmnInfoInit_Debug23a(struct dm_odm_t *pDM_Odm); + +void odm_CmnInfoHook_Debug23a(struct dm_odm_t *pDM_Odm); + +void odm_CmnInfoUpdate_Debug23a(struct dm_odm_t *pDM_Odm); + +/* START---------------DIG--------------------------- */ +void odm_FalseAlarmCounterStatistics23a(struct dm_odm_t *pDM_Odm); + +void odm_DIG23aInit(struct dm_odm_t *pDM_Odm); + +void odm_DIG23a(struct dm_odm_t *pDM_Odm); + +void odm_CCKPacketDetectionThresh23a(struct dm_odm_t *pDM_Odm); +/* END---------------DIG--------------------------- */ + +/* START-------BB POWER SAVE----------------------- */ +void odm23a_DynBBPSInit(struct dm_odm_t *pDM_Odm); + +void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm); + +void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm); +/* END---------BB POWER SAVE----------------------- */ + +void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm); + +void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm); + +void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm); + +void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm); + +void odm_DynamicTxPower23aRestorePowerIndex(struct dm_odm_t *pDM_Odm); + +void odm_DynamicTxPower23aSavePowerIndex(struct dm_odm_t *pDM_Odm); + +void odm_DynamicTxPower23aWritePowerIndex(struct dm_odm_t *pDM_Odm, + u8 Value); + +void odm_DynamicTxPower23a_92C(struct dm_odm_t *pDM_Odm); + +void odm_DynamicTxPower23a_92D(struct dm_odm_t *pDM_Odm); + +void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm); + +void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm); + +void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm); +void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm); + +void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm); +void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm); + +void odm_SwAntDivInit(struct dm_odm_t *pDM_Odm); + +void odm_SwAntDivInit_NIC(struct dm_odm_t *pDM_Odm); + +void odm_SwAntDivChkAntSwitch(struct dm_odm_t *pDM_Odm, u8 Step); + +void odm_SwAntDivChkAntSwitchNIC(struct dm_odm_t *pDM_Odm, + u8 Step + ); + +void odm_SwAntDivChkAntSwitchCallback23a(unsigned long data); + +void odm_GlobalAdapterCheck(void); + +void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm); + +void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm); + +void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm); + +void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm); + +void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm); + +void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm); + +void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm); + +void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm); + +void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm); +void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm); + +void odm_EdcaTurboCheck23aCE23a(struct dm_odm_t *pDM_Odm); + +#define RxDefaultAnt1 0x65a9 +#define RxDefaultAnt2 0x569a + +void odm_InitHybridAntDiv23a(struct dm_odm_t *pDM_Odm); + +bool odm_StaDefAntSel(struct dm_odm_t *pDM_Odm, + u32 OFDM_Ant1_Cnt, + u32 OFDM_Ant2_Cnt, + u32 CCK_Ant1_Cnt, + u32 CCK_Ant2_Cnt, + u8 *pDefAnt + ); + +void odm_SetRxIdleAnt(struct dm_odm_t *pDM_Odm, + u8 Ant, + bool bDualPath +); + +void odm_HwAntDiv23a(struct dm_odm_t *pDM_Odm); + +/* 3 Export Interface */ + +/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ +void ODM23a_DMInit(struct dm_odm_t *pDM_Odm) +{ + /* For all IC series */ + odm_CommonInfoSelfInit23a(pDM_Odm); + odm_CmnInfoInit_Debug23a(pDM_Odm); + odm_DIG23aInit(pDM_Odm); + odm_RateAdaptiveMaskInit23a(pDM_Odm); + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + odm23a_DynBBPSInit(pDM_Odm); + odm_DynamicTxPower23aInit(pDM_Odm); + odm_TXPowerTrackingInit23a(pDM_Odm); + ODM_EdcaTurboInit23a(pDM_Odm); + if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || + (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || + (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) + odm_InitHybridAntDiv23a(pDM_Odm); + else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) + odm_SwAntDivInit(pDM_Odm); + } +} + +/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ +/* You can not add any dummy function here, be care, you can only use DM structure */ +/* to perform any new ODM_DM. */ +void ODM_DMWatchdog23a(struct dm_odm_t *pDM_Odm) +{ + /* 2012.05.03 Luke: For all IC series */ + odm_GlobalAdapterCheck(); + odm_CmnInfoHook_Debug23a(pDM_Odm); + odm_CmnInfoUpdate_Debug23a(pDM_Odm); + odm_CommonInfoSelfUpdate23a(pDM_Odm); + odm_FalseAlarmCounterStatistics23a(pDM_Odm); + odm_RSSIMonitorCheck23a(pDM_Odm); + + /* 8723A or 8189ES platform */ + /* NeilChen--2012--08--24-- */ + /* Fix Leave LPS issue */ + if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/* in LPS mode */ + (pDM_Odm->SupportICType & (ODM_RTL8723A))) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG23a is in LPS mode\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); + odm_DIG23abyRSSI_LPS(pDM_Odm); + } else { + odm_DIG23a(pDM_Odm); + } + + odm_CCKPacketDetectionThresh23a(pDM_Odm); + + if (*(pDM_Odm->pbPowerSaving)) + return; + + odm_RefreshRateAdaptiveMask23a(pDM_Odm); + + odm_DynamicBBPowerSaving23a(pDM_Odm); + if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || + (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || + (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) + odm_HwAntDiv23a(pDM_Odm); + else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) + odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + ODM_TXPowerTrackingCheck23a(pDM_Odm); + odm_EdcaTurboCheck23a(pDM_Odm); + odm_DynamicTxPower23a(pDM_Odm); + } + + odm_dtc(pDM_Odm); +} + +/* */ +/* Init /.. Fixed HW value. Only init time. */ +/* */ +void ODM_CmnInfoInit23a(struct dm_odm_t *pDM_Odm, + enum odm_cmninfo CmnInfo, + u32 Value + ) +{ + /* ODM_RT_TRACE(pDM_Odm,); */ + + /* */ + /* This section is used for init value */ + /* */ + switch (CmnInfo) { + /* Fixed ODM value. */ + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u32)Value; + break; + case ODM_CMNINFO_PLATFORM: + break; + case ODM_CMNINFO_INTERFACE: + pDM_Odm->SupportInterface = (u8)Value; + break; + case ODM_CMNINFO_MP_TEST_CHIP: + pDM_Odm->bIsMPChip = (u8)Value; + break; + case ODM_CMNINFO_IC_TYPE: + pDM_Odm->SupportICType = Value; + break; + case ODM_CMNINFO_CUT_VER: + pDM_Odm->CutVersion = (u8)Value; + break; + case ODM_CMNINFO_FAB_VER: + pDM_Odm->FabVersion = (u8)Value; + break; + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u8)Value; + break; + case ODM_CMNINFO_RF_ANTENNA_TYPE: + pDM_Odm->AntDivType = (u8)Value; + break; + case ODM_CMNINFO_BOARD_TYPE: + pDM_Odm->BoardType = (u8)Value; + break; + case ODM_CMNINFO_EXT_LNA: + pDM_Odm->ExtLNA = (u8)Value; + break; + case ODM_CMNINFO_EXT_PA: + pDM_Odm->ExtPA = (u8)Value; + break; + case ODM_CMNINFO_EXT_TRSW: + pDM_Odm->ExtTRSW = (u8)Value; + break; + case ODM_CMNINFO_PATCH_ID: + pDM_Odm->PatchID = (u8)Value; + break; + case ODM_CMNINFO_BINHCT_TEST: + pDM_Odm->bInHctTest = (bool)Value; + break; + case ODM_CMNINFO_BWIFI_TEST: + pDM_Odm->bWIFITest = (bool)Value; + break; + case ODM_CMNINFO_SMART_CONCURRENT: + pDM_Odm->bDualMacSmartConcurrent = (bool)Value; + break; + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; + } + + /* */ + /* Tx power tracking BB swing table. */ + /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */ + /* */ + pDM_Odm->BbSwingIdxOfdm = 12; /* Set defalut value as index 12. */ + pDM_Odm->BbSwingIdxOfdmCurrent = 12; + pDM_Odm->BbSwingFlagOfdm = false; + +} + +void ODM23a_CmnInfoHook(struct dm_odm_t *pDM_Odm, + enum odm_cmninfo CmnInfo, + void *pValue + ) +{ + /* Hook call by reference pointer. */ + switch (CmnInfo) { + /* Dynamic call by reference pointer. */ + case ODM_CMNINFO_MAC_PHY_MODE: + pDM_Odm->pMacPhyMode = (u8 *)pValue; + break; + case ODM_CMNINFO_TX_UNI: + pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue; + break; + case ODM_CMNINFO_RX_UNI: + pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue; + break; + case ODM_CMNINFO_WM_MODE: + pDM_Odm->pWirelessMode = (u8 *)pValue; + break; + case ODM_CMNINFO_BAND: + pDM_Odm->pBandType = (u8 *)pValue; + break; + case ODM_CMNINFO_SEC_CHNL_OFFSET: + pDM_Odm->pSecChOffset = (u8 *)pValue; + break; + case ODM_CMNINFO_SEC_MODE: + pDM_Odm->pSecurity = (u8 *)pValue; + break; + case ODM_CMNINFO_BW: + pDM_Odm->pBandWidth = (u8 *)pValue; + break; + case ODM_CMNINFO_CHNL: + pDM_Odm->pChannel = (u8 *)pValue; + break; + case ODM_CMNINFO_DMSP_GET_VALUE: + pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue; + break; + case ODM_CMNINFO_BUDDY_ADAPTOR: + pDM_Odm->pBuddyAdapter = (struct rtw_adapter **)pValue; + break; + case ODM_CMNINFO_DMSP_IS_MASTER: + pDM_Odm->pbMasterOfDMSP = (bool *)pValue; + break; + case ODM_CMNINFO_SCAN: + pDM_Odm->pbScanInProcess = (bool *)pValue; + break; + case ODM_CMNINFO_POWER_SAVING: + pDM_Odm->pbPowerSaving = (bool *)pValue; + break; + case ODM_CMNINFO_ONE_PATH_CCA: + pDM_Odm->pOnePathCCA = (u8 *)pValue; + break; + case ODM_CMNINFO_DRV_STOP: + pDM_Odm->pbDriverStopped = (bool *)pValue; + break; + case ODM_CMNINFO_PNP_IN: + pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue; + break; + case ODM_CMNINFO_INIT_ON: + pDM_Odm->pinit_adpt_in_progress = (bool *)pValue; + break; + case ODM_CMNINFO_ANT_TEST: + pDM_Odm->pAntennaTest = (u8 *)pValue; + break; + case ODM_CMNINFO_NET_CLOSED: + pDM_Odm->pbNet_closed = (bool *)pValue; + break; + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; + } +} + +void ODM_CmnInfoPtrArrayHook23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo CmnInfo, + u16 Index, void *pValue) +{ + /* Hook call by reference pointer. */ + switch (CmnInfo) { + /* Dynamic call by reference pointer. */ + case ODM_CMNINFO_STA_STATUS: + pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue; + break; + /* To remove the compiler warning, must add an empty default statement to handle the other values. */ + default: + /* do nothing */ + break; + } +} + +/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ +void ODM_CmnInfoUpdate23a(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value) +{ + /* This init variable may be changed in run time. */ + switch (CmnInfo) { + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u32)Value; + break; + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u8)Value; + break; + case ODM_CMNINFO_WIFI_DIRECT: + pDM_Odm->bWIFI_Direct = (bool)Value; + break; + case ODM_CMNINFO_WIFI_DISPLAY: + pDM_Odm->bWIFI_Display = (bool)Value; + break; + case ODM_CMNINFO_LINK: + pDM_Odm->bLinked = (bool)Value; + break; + case ODM_CMNINFO_RSSI_MIN: + pDM_Odm->RSSI_Min = (u8)Value; + break; + case ODM_CMNINFO_DBG_COMP: + pDM_Odm->DebugComponents = Value; + break; + case ODM_CMNINFO_DBG_LEVEL: + pDM_Odm->DebugLevel = (u32)Value; + break; + case ODM_CMNINFO_RA_THRESHOLD_HIGH: + pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; + break; + case ODM_CMNINFO_RA_THRESHOLD_LOW: + pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; + break; + } + +} + +void odm_CommonInfoSelfInit23a(struct dm_odm_t *pDM_Odm + ) +{ + pDM_Odm->bCckHighPower = (bool) ODM_GetBBReg(pDM_Odm, 0x824, BIT9); + pDM_Odm->RFPathRxEnable = (u8) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F); + if (pDM_Odm->SupportICType & (ODM_RTL8723A)) + pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; + + ODM_InitDebugSetting23a(pDM_Odm); +} + +void odm_CommonInfoSelfUpdate23a(struct dm_odm_t *pDM_Odm) +{ + u8 EntryCnt = 0; + u8 i; + struct sta_info *pEntry; + + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) { + if (*(pDM_Odm->pSecChOffset) == 1) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) - 2; + else if (*(pDM_Odm->pSecChOffset) == 2) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) + 2; + } else { + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); + } + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if (IS_STA_VALID(pEntry)) + EntryCnt++; + } + if (EntryCnt == 1) + pDM_Odm->bOneEntryOnly = true; + else + pDM_Odm->bOneEntryOnly = false; +} + +void odm_CmnInfoInit_Debug23a(struct dm_odm_t *pDM_Odm) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug23a ==>\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent)); + +} + +void odm_CmnInfoHook_Debug23a(struct dm_odm_t *pDM_Odm) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug23a ==>\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast =%llu\n", *(pDM_Odm->pNumTxBytesUnicast))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast =%llu\n", *(pDM_Odm->pNumRxBytesUnicast))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode = 0x%x\n", *(pDM_Odm->pWirelessMode))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset =%d\n", *(pDM_Odm->pSecChOffset))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity =%d\n", *(pDM_Odm->pSecurity))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth =%d\n", *(pDM_Odm->pBandWidth))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel =%d\n", *(pDM_Odm->pChannel))); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess =%d\n", *(pDM_Odm->pbScanInProcess))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving =%d\n", *(pDM_Odm->pbPowerSaving))); +} + +void odm_CmnInfoUpdate_Debug23a(struct dm_odm_t *pDM_Odm) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug23a ==>\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct =%d\n", pDM_Odm->bWIFI_Direct)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display =%d\n", pDM_Odm->bWIFI_Display)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked =%d\n", pDM_Odm->bLinked)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min =%d\n", pDM_Odm->RSSI_Min)); +} + +void ODM_Write_DIG23a(struct dm_odm_t *pDM_Odm, + u8 CurrentIGI + ) +{ + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_REG(IGI_A, pDM_Odm) = 0x%x, ODM_BIT(IGI, pDM_Odm) = 0x%x \n", + ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm))); + + if (pDM_DigTable->CurIGValue != CurrentIGI) { + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x). \n", CurrentIGI)); + pDM_DigTable->CurIGValue = CurrentIGI; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("ODM_Write_DIG23a():CurrentIGI = 0x%x \n", CurrentIGI)); +} + +/* Need LPS mode for CE platform --2012--08--24--- */ +/* 8723AS/8189ES */ +void odm_DIG23abyRSSI_LPS(struct dm_odm_t *pDM_Odm) +{ + struct rtw_adapter *pAdapter = pDM_Odm->Adapter; + struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + u8 RSSI_Lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ + u8 bFwCurrentInPSMode = false; + u8 CurrentIGI = pDM_Odm->RSSI_Min; + + if (!(pDM_Odm->SupportICType & (ODM_RTL8723A))) + return; + + CurrentIGI = CurrentIGI+RSSI_OFFSET_DIG; + bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode; + + /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG_LPS, ODM_DBG_LOUD, ("odm_DIG23a() ==>\n")); */ + + /* Using FW PS mode to make IGI */ + if (bFwCurrentInPSMode) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG23a is in LPS mode\n")); + /* Adjust by FA in LPS MODE */ + if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS) + CurrentIGI = CurrentIGI+2; + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) + CurrentIGI = CurrentIGI+1; + else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) + CurrentIGI = CurrentIGI-1; + } else { + CurrentIGI = RSSI_Lower; + } + + /* Lower bound checking */ + + /* RSSI Lower bound check */ + if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC) + RSSI_Lower = (pDM_Odm->RSSI_Min-10); + else + RSSI_Lower = DM_DIG_MIN_NIC; + + /* Upper and Lower Bound checking */ + if (CurrentIGI > DM_DIG_MAX_NIC) + CurrentIGI = DM_DIG_MAX_NIC; + else if (CurrentIGI < RSSI_Lower) + CurrentIGI = RSSI_Lower; + + ODM_Write_DIG23a(pDM_Odm, CurrentIGI);/* ODM_Write_DIG23a(pDM_Odm, pDM_DigTable->CurIGValue); */ + +} + +void odm_DIG23aInit(struct dm_odm_t *pDM_Odm) +{ + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + + pDM_DigTable->CurIGValue = (u8) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)); + pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; + pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; + pDM_DigTable->FALowThresh = DM_FALSEALARM_THRESH_LOW; + pDM_DigTable->FAHighThresh = DM_FALSEALARM_THRESH_HIGH; + if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; + } else { + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; + } + pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; + pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; + pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; + pDM_DigTable->PreCCK_CCAThres = 0xFF; + pDM_DigTable->CurCCK_CCAThres = 0x83; + pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; + pDM_DigTable->LargeFAHit = 0; + pDM_DigTable->Recover_cnt = 0; + pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; + pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; + pDM_DigTable->bMediaConnect_0 = false; + pDM_DigTable->bMediaConnect_1 = false; + + /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */ + pDM_Odm->bDMInitialGainEnable = true; + +} + +void odm_DIG23a(struct dm_odm_t *pDM_Odm) +{ + + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + u8 DIG_Dynamic_MIN; + u8 DIG_MaxOfMin; + bool FirstConnect, FirstDisConnect; + u8 dm_dig_max, dm_dig_min; + u8 CurrentIGI = pDM_DigTable->CurIGValue; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() ==>\n")); + /* if (!(pDM_Odm->SupportAbility & (ODM_BB_DIG|ODM_BB_FA_CNT))) */ + if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("odm_DIG23a() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); + return; + } + + if (*(pDM_Odm->pbScanInProcess)) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() Return: In Scan Progress \n")); + return; + } + + /* add by Neil Chen to avoid PSD is processing */ + if (!pDM_Odm->bDMInitialGainEnable) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() Return: PSD is Processing \n")); + return; + } + + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; + FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); + + /* 1 Boundary Decision */ + if ((pDM_Odm->SupportICType & (ODM_RTL8723A)) && + ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) { + dm_dig_max = DM_DIG_MAX_NIC_HP; + dm_dig_min = DM_DIG_MIN_NIC_HP; + DIG_MaxOfMin = DM_DIG_MAX_AP_HP; + } else { + dm_dig_max = DM_DIG_MAX_NIC; + dm_dig_min = DM_DIG_MIN_NIC; + DIG_MaxOfMin = DM_DIG_MAX_AP; + } + + if (pDM_Odm->bLinked) { + /* 2 8723A Series, offset need to be 10 */ + if (pDM_Odm->SupportICType == (ODM_RTL8723A)) { + /* 2 Upper Bound */ + if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC) + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC) + pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; + + /* 2 If BT is Concurrent, need to set Lower Bound */ + DIG_Dynamic_MIN = DM_DIG_MIN_NIC; + } else { + /* 2 Modify DIG upper bound */ + if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max) + pDM_DigTable->rx_gain_range_max = dm_dig_max; + else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min) + pDM_DigTable->rx_gain_range_max = dm_dig_min; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; + + /* 2 Modify DIG lower bound */ + if (pDM_Odm->bOneEntryOnly) { + if (pDM_Odm->RSSI_Min < dm_dig_min) + DIG_Dynamic_MIN = dm_dig_min; + else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin) + DIG_Dynamic_MIN = DIG_MaxOfMin; + else + DIG_Dynamic_MIN = pDM_Odm->RSSI_Min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("odm_DIG23a() : bOneEntryOnly = true, DIG_Dynamic_MIN = 0x%x\n", + DIG_Dynamic_MIN)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("odm_DIG23a() : pDM_Odm->RSSI_Min =%d\n", + pDM_Odm->RSSI_Min)); + } else { + DIG_Dynamic_MIN = dm_dig_min; + } + } + } else { + pDM_DigTable->rx_gain_range_max = dm_dig_max; + DIG_Dynamic_MIN = dm_dig_min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() : No Link\n")); + } + + /* 1 Modify DIG lower bound, deal with abnormally large false alarm */ + if (pFalseAlmCnt->Cnt_all > 10000) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("dm_DIG(): Abnornally false alarm case. \n")); + + if (pDM_DigTable->LargeFAHit != 3) + pDM_DigTable->LargeFAHit++; + if (pDM_DigTable->ForbiddenIGI < CurrentIGI) { + pDM_DigTable->ForbiddenIGI = CurrentIGI; + pDM_DigTable->LargeFAHit = 1; + } + + if (pDM_DigTable->LargeFAHit >= 3) { + if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max) + pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; + else + pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); + pDM_DigTable->Recover_cnt = 3600; /* 3600 = 2hr */ + } + } else { + /* Recovery mechanism for IGI lower bound */ + if (pDM_DigTable->Recover_cnt != 0) { + pDM_DigTable->Recover_cnt--; + } else { + if (pDM_DigTable->LargeFAHit < 3) { + if ((pDM_DigTable->ForbiddenIGI - 1) < DIG_Dynamic_MIN) { + pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ + pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("odm_DIG23a(): Normal Case: At Lower Bound\n")); + } else { + pDM_DigTable->ForbiddenIGI--; + pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, + ("odm_DIG23a(): Normal Case: Approach Lower Bound\n")); + } + } else { + pDM_DigTable->LargeFAHit = 0; + } + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): pDM_DigTable->LargeFAHit =%d\n", pDM_DigTable->LargeFAHit)); + + /* 1 Adjust initial gain by false alarm */ + if (pDM_Odm->bLinked) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG AfterLink\n")); + if (FirstConnect) { + CurrentIGI = pDM_Odm->RSSI_Min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n")); + } else { + if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) + CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) + CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ + else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) + CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue-1; */ + } + } else { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG BeforeLink\n")); + if (FirstDisConnect) { + CurrentIGI = pDM_DigTable->rx_gain_range_min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): First DisConnect \n")); + } else { + /* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */ + if (pFalseAlmCnt->Cnt_all > 10000) + CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ + else if (pFalseAlmCnt->Cnt_all > 8000) + CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ + else if (pFalseAlmCnt->Cnt_all < 500) + CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue-1; */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): England DIG \n")); + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG End Adjust IGI\n")); + /* 1 Check initial gain by upper/lower bound */ + if (CurrentIGI > pDM_DigTable->rx_gain_range_max) + CurrentIGI = pDM_DigTable->rx_gain_range_max; + if (CurrentIGI < pDM_DigTable->rx_gain_range_min) + CurrentIGI = pDM_DigTable->rx_gain_range_min; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): rx_gain_range_max = 0x%x, rx_gain_range_min = 0x%x\n", + pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): TotalFA =%d\n", pFalseAlmCnt->Cnt_all)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): CurIGValue = 0x%x\n", CurrentIGI)); + + /* 2 High power RSSI threshold */ + + ODM_Write_DIG23a(pDM_Odm, CurrentIGI);/* ODM_Write_DIG23a(pDM_Odm, pDM_DigTable->CurIGValue); */ + pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; +} + +/* 3 ============================================================ */ +/* 3 FASLE ALARM CHECK */ +/* 3 ============================================================ */ + +void odm_FalseAlarmCounterStatistics23a(struct dm_odm_t *pDM_Odm) +{ + u32 ret_value; + struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; + + if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) + return; + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + /* hold ofdm counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */ + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); + FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff); + FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); + FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff); + FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); + FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff); + FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); + FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff); + + FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + + FalseAlmCnt->Cnt_Rate_Illegal + + FalseAlmCnt->Cnt_Crc8_fail + + FalseAlmCnt->Cnt_Mcs_fail + + FalseAlmCnt->Cnt_Fast_Fsync + + FalseAlmCnt->Cnt_SB_Search_fail; + /* hold cck counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1); + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); + FalseAlmCnt->Cnt_Cck_fail = ret_value; + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); + FalseAlmCnt->Cnt_Cck_fail += (ret_value & 0xff) << 8; + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); + FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8); + + FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync + + FalseAlmCnt->Cnt_SB_Search_fail + + FalseAlmCnt->Cnt_Parity_Fail + + FalseAlmCnt->Cnt_Rate_Illegal + + FalseAlmCnt->Cnt_Crc8_fail + + FalseAlmCnt->Cnt_Mcs_fail + + FalseAlmCnt->Cnt_Cck_fail); + + FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; + + if (pDM_Odm->SupportICType >= ODM_RTL8723A) { + /* reset false alarm counter registers */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0); + /* update ofdm counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); /* update page C counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); /* update page D counter */ + + /* reset CCK CCA counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2); + /* reset CCK FA counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2); + } + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics23a\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Fast_Fsync =%d, Cnt_SB_Search_fail =%d\n", + FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Parity_Fail =%d, Cnt_Rate_Illegal =%d\n", + FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Crc8_fail =%d, Cnt_Mcs_fail =%d\n", + FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail)); + } else { /* FOR ODM_IC_11AC_SERIES */ + /* read OFDM FA counter */ + FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord); + FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord); + FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail; + + /* reset OFDM FA coutner */ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0); + /* reset CCK FA counter */ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1); + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail =%d\n", FalseAlmCnt->Cnt_Cck_fail)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm =%d\n", FalseAlmCnt->Cnt_all)); +} + +/* 3 ============================================================ */ +/* 3 CCK Packet Detect Threshold */ +/* 3 ============================================================ */ + +void odm_CCKPacketDetectionThresh23a(struct dm_odm_t *pDM_Odm) +{ + struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; + u8 CurCCK_CCAThres; + + if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT))) + return; + + if (pDM_Odm->ExtLNA) + return; + + if (pDM_Odm->bLinked) { + if (pDM_Odm->RSSI_Min > 25) { + CurCCK_CCAThres = 0xcd; + } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) { + CurCCK_CCAThres = 0x83; + } else { + if (FalseAlmCnt->Cnt_Cck_fail > 1000) + CurCCK_CCAThres = 0x83; + else + CurCCK_CCAThres = 0x40; + } + } else { + if (FalseAlmCnt->Cnt_Cck_fail > 1000) + CurCCK_CCAThres = 0x83; + else + CurCCK_CCAThres = 0x40; + } + + ODM_Write_CCK_CCA_Thres23a(pDM_Odm, CurCCK_CCAThres); +} + +void ODM_Write_CCK_CCA_Thres23a(struct dm_odm_t *pDM_Odm, u8 CurCCK_CCAThres) +{ + struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable; + + if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) + ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres); + pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; + pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; + +} + +/* 3 ============================================================ */ +/* 3 BB Power Save */ +/* 3 ============================================================ */ +void odm23a_DynBBPSInit(struct dm_odm_t *pDM_Odm) +{ + struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable; + + pDM_PSTable->PreCCAState = CCA_MAX; + pDM_PSTable->CurCCAState = CCA_MAX; + pDM_PSTable->PreRFState = RF_MAX; + pDM_PSTable->CurRFState = RF_MAX; + pDM_PSTable->Rssi_val_min = 0; + pDM_PSTable->initialize = 0; +} + +void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm) +{ + return; +} + +void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm) +{ + struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable; + + if (pDM_Odm->RSSI_Min != 0xFF) { + if (pDM_PSTable->PreCCAState == CCA_2R) { + if (pDM_Odm->RSSI_Min >= 35) + pDM_PSTable->CurCCAState = CCA_1R; + else + pDM_PSTable->CurCCAState = CCA_2R; + } else { + if (pDM_Odm->RSSI_Min <= 30) + pDM_PSTable->CurCCAState = CCA_2R; + else + pDM_PSTable->CurCCAState = CCA_1R; + } + } else { + pDM_PSTable->CurCCAState = CCA_MAX; + } + + if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) { + if (pDM_PSTable->CurCCAState == CCA_1R) { + if (pDM_Odm->RFType == ODM_2T2R) + ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13); + else + ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23); + } else { + ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33); + /* PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x63); */ + } + pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState; + } +} + +void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal) +{ + struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable; + u8 Rssi_Up_bound = 30 ; + u8 Rssi_Low_bound = 25; + if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */ + Rssi_Up_bound = 50 ; + Rssi_Low_bound = 45; + } + if (pDM_PSTable->initialize == 0) { + + pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14; + pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3; + pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24; + pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12; + /* Reg818 = PHY_QueryBBReg(pAdapter, 0x818, bMaskDWord); */ + pDM_PSTable->initialize = 1; + } + + if (!bForceInNormal) { + if (pDM_Odm->RSSI_Min != 0xFF) { + if (pDM_PSTable->PreRFState == RF_Normal) { + if (pDM_Odm->RSSI_Min >= Rssi_Up_bound) + pDM_PSTable->CurRFState = RF_Save; + else + pDM_PSTable->CurRFState = RF_Normal; + } else { + if (pDM_Odm->RSSI_Min <= Rssi_Low_bound) + pDM_PSTable->CurRFState = RF_Normal; + else + pDM_PSTable->CurRFState = RF_Save; + } + } else { + pDM_PSTable->CurRFState = RF_MAX; + } + } else { + pDM_PSTable->CurRFState = RF_Normal; + } + + if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) { + if (pDM_PSTable->CurRFState == RF_Save) { + /* 8723 RSSI report will be wrong. Set 0x874[5]= 1 when enter BB power saving mode. */ + /* Suggested by SD3 Yu-Nan. 2011.01.20. */ + if (pDM_Odm->SupportICType == ODM_RTL8723A) + ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x1); /* Reg874[5]= 1b'1 */ + ODM_SetBBReg(pDM_Odm, 0x874, 0x1C0000, 0x2); /* Reg874[20:18]= 3'b010 */ + ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); /* RegC70[3]= 1'b0 */ + ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]= 0x63 */ + ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]= 2'b10 */ + ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]= 0x3 */ + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); /* Reg818[28]= 1'b0 */ + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); /* Reg818[28]= 1'b1 */ + } else { + ODM_SetBBReg(pDM_Odm, 0x874, 0x1CC000, pDM_PSTable->Reg874); + ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70); + ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C); + ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74); + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); + + if (pDM_Odm->SupportICType == ODM_RTL8723A) + ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x0); /* Reg874[5]= 1b'0 */ + } + pDM_PSTable->PreRFState = pDM_PSTable->CurRFState; + } +} + +/* 3 ============================================================ */ +/* 3 RATR MASK */ +/* 3 ============================================================ */ +/* 3 ============================================================ */ +/* 3 Rate Adaptive */ +/* 3 ============================================================ */ + +void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm) +{ + struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive; + + pOdmRA->Type = DM_Type_ByDriver; + if (pOdmRA->Type == DM_Type_ByDriver) + pDM_Odm->bUseRAMask = true; + else + pDM_Odm->bUseRAMask = false; + + pOdmRA->RATRState = DM_RATR_STA_INIT; + pOdmRA->HighRSSIThresh = 50; + pOdmRA->LowRSSIThresh = 20; +} + +u32 ODM_Get_Rate_Bitmap23a(struct dm_odm_t *pDM_Odm, + u32 macid, + u32 ra_mask, + u8 rssi_level) +{ + struct sta_info *pEntry; + u32 rate_bitmap = 0x0fffffff; + u8 WirelessMode; + /* u8 WirelessMode =*(pDM_Odm->pWirelessMode); */ + + pEntry = pDM_Odm->pODM_StaInfo[macid]; + if (!IS_STA_VALID(pEntry)) + return ra_mask; + + WirelessMode = pEntry->wireless_mode; + + switch (WirelessMode) { + case ODM_WM_B: + if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ + rate_bitmap = 0x0000000d; + else + rate_bitmap = 0x0000000f; + break; + case (ODM_WM_A|ODM_WM_G): + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else + rate_bitmap = 0x00000ff0; + break; + case (ODM_WM_B|ODM_WM_G): + if (rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else if (rssi_level == DM_RATR_STA_MIDDLE) + rate_bitmap = 0x00000ff0; + else + rate_bitmap = 0x00000ff5; + break; + case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G): + case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G): + if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) { + if (rssi_level == DM_RATR_STA_HIGH) { + rate_bitmap = 0x000f0000; + } else if (rssi_level == DM_RATR_STA_MIDDLE) { + rate_bitmap = 0x000ff000; + } else { + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x000ff015; + else + rate_bitmap = 0x000ff005; + } + } else { + if (rssi_level == DM_RATR_STA_HIGH) { + rate_bitmap = 0x0f8f0000; + } else if (rssi_level == DM_RATR_STA_MIDDLE) { + rate_bitmap = 0x0f8ff000; + } else { + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x0f8ff015; + else + rate_bitmap = 0x0f8ff005; + } + } + break; + default: + /* case WIRELESS_11_24N: */ + /* case WIRELESS_11_5N: */ + if (pDM_Odm->RFType == RF_1T2R) + rate_bitmap = 0x000fffff; + else + rate_bitmap = 0x0fffffff; + break; + } + + /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n", __FUNCTION__, rssi_level, WirelessMode, rate_bitmap); */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n", rssi_level, WirelessMode, rate_bitmap)); + + return rate_bitmap; + +} + +/*----------------------------------------------------------------------------- + * Function: odm_RefreshRateAdaptiveMask23a() + * + * Overview: Update rate table mask according to rssi + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + *When Who Remark + *05/27/2009 hpfan Create Version 0. + * + *---------------------------------------------------------------------------*/ +void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm) +{ + if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) + return; + /* */ + /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ + /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ + /* HW dynamic mechanism. */ + /* */ + odm_RefreshRateAdaptiveMask23aCE23a(pDM_Odm); +} + +void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm) +{ + u8 i; + struct rtw_adapter *pAdapter = pDM_Odm->Adapter; + + if (pAdapter->bDriverStopped) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, + ("<---- odm_RefreshRateAdaptiveMask23a(): driver is going to unload\n")); + return; + } + + if (!pDM_Odm->bUseRAMask) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, + ("<---- odm_RefreshRateAdaptiveMask23a(): driver does not control rate adaptive mask\n")); + return; + } + + /* printk("==> %s \n", __FUNCTION__); */ + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i]; + if (IS_STA_VALID(pstat)) { + if (ODM_RAStateCheck23a(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, + ("RSSI:%d, RSSI_LEVEL:%d\n", + pstat->rssi_stat.UndecoratedSmoothedPWDB, + pstat->rssi_level)); + rtw_hal_update_ra_mask23a(pstat, pstat->rssi_level); + } + + } + } + +} + +void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm) +{ +} + +/* Return Value: bool */ +/* - true: RATRState is changed. */ +bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate, + u8 *pRATRState) +{ + struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive; + const u8 GoUpGap = 5; + u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; + u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; + u8 RATRState; + + /* Threshold Adjustment: */ + /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ + /* Here GoUpGap is added to solve the boundary's level alternation issue. */ + switch (*pRATRState) { + case DM_RATR_STA_INIT: + case DM_RATR_STA_HIGH: + break; + case DM_RATR_STA_MIDDLE: + HighRSSIThreshForRA += GoUpGap; + break; + case DM_RATR_STA_LOW: + HighRSSIThreshForRA += GoUpGap; + LowRSSIThreshForRA += GoUpGap; + break; + default: + ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState)); + break; + } + + /* Decide RATRState by RSSI. */ + if (RSSI > HighRSSIThreshForRA) + RATRState = DM_RATR_STA_HIGH; + else if (RSSI > LowRSSIThreshForRA) + RATRState = DM_RATR_STA_MIDDLE; + else + RATRState = DM_RATR_STA_LOW; + + if (*pRATRState != RATRState || bForceUpdate) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, + ("RSSI Level %d -> %d\n", *pRATRState, RATRState)); + *pRATRState = RATRState; + return true; + } + return false; +} + +/* 3 ============================================================ */ +/* 3 Dynamic Tx Power */ +/* 3 ============================================================ */ + +void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + + pdmpriv->bDynamicTxPowerEnable = false; + + pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; +} + +void odm_DynamicTxPower23aSavePowerIndex(struct dm_odm_t *pDM_Odm) +{ + u8 index; + u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + for (index = 0; index < 6; index++) + pdmpriv->PowerIndex_backup[index] = rtw_read8(Adapter, Power_Index_REG[index]); +} + +void odm_DynamicTxPower23aRestorePowerIndex(struct dm_odm_t *pDM_Odm) +{ + u8 index; + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + struct dm_priv *pdmpriv = &pHalData->dmpriv; + for (index = 0; index < 6; index++) + rtw_write8(Adapter, Power_Index_REG[index], pdmpriv->PowerIndex_backup[index]); +} + +void odm_DynamicTxPower23aWritePowerIndex(struct dm_odm_t *pDM_Odm, + u8 Value) +{ + + u8 index; + u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + + for (index = 0; index < 6; index++) + ODM_Write1Byte(pDM_Odm, Power_Index_REG[index], Value); + +} + +void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_DynamicTxPower23a_92C(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_DynamicTxPower23a_92D(struct dm_odm_t *pDM_Odm) +{ +} + +/* 3 ============================================================ */ +/* 3 RSSI Monitor */ +/* 3 ============================================================ */ + +void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm) +{ + /* For AP/ADSL use struct rtl8723a_priv * */ + /* For CE/NIC use struct rtw_adapter * */ + + if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) + return; + + /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ + /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ + /* HW dynamic mechanism. */ + odm_RSSIMonitorCheck23aCE(pDM_Odm); +} /* odm_RSSIMonitorCheck23a */ + +void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm) +{ +} + +static void +FindMinimumRSSI( + struct rtw_adapter *pAdapter + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + + /* 1 1.Determine the minimum RSSI */ + + if ((!pDM_Odm->bLinked) && + (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) + pdmpriv->MinUndecoratedPWDBForDM = 0; + else + pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; +} + +void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + int i; + int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; + u8 sta_cnt = 0; + u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ + struct sta_info *psta; + + if (!pDM_Odm->bLinked) + return; + + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { + psta = pDM_Odm->pODM_StaInfo[i]; + if (IS_STA_VALID(psta)) { + if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) + tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) + tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); + } + } + + for (i = 0; i < sta_cnt; i++) { + if (PWDB_rssi[i] != (0)) { + if (pHalData->fw_ractrl) /* Report every sta's RSSI to FW */ + rtl8723a_set_rssi_cmd(Adapter, (u8 *)&PWDB_rssi[i]); + } + } + + if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; + else + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; + + if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ + pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; + else + pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; + + FindMinimumRSSI(Adapter);/* get pdmpriv->MinUndecoratedPWDBForDM */ + + ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); +} + +void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm) +{ +} + +void ODM_InitAllTimers(struct dm_odm_t *pDM_Odm) +{ + setup_timer(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, + odm_SwAntDivChkAntSwitchCallback23a, (unsigned long)pDM_Odm); +} + +void ODM_CancelAllTimers(struct dm_odm_t *pDM_Odm) +{ + del_timer_sync(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); +} + +void ODM_ReleaseAllTimers(struct dm_odm_t *pDM_Odm) +{ + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); +} + +/* endif */ +/* 3 ============================================================ */ +/* 3 Tx Power Tracking */ +/* 3 ============================================================ */ + +void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm) +{ + odm_TXPowerTrackingThermalMeterInit23a(pDM_Odm); +} + +void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + + pdmpriv->bTXPowerTracking = true; + pdmpriv->TXPowercount = 0; + pdmpriv->bTXPowerTrackingInit = false; + pdmpriv->TxPowerTrackControl = true; + MSG_8723A("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl); + + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; +} + +void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm) +{ + /* For AP/ADSL use struct rtl8723a_priv * */ + /* For CE/NIC use struct rtw_adapter * */ + + /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ + /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ + /* HW dynamic mechanism. */ + odm_TXPowerTrackingCheckCE23a(pDM_Odm); +} + +void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm) +{ +} + +/* antenna mapping info */ +/* 1: right-side antenna */ +/* 2/0: left-side antenna */ +/* PpDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 */ +/* PpDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 */ +/* We select left antenna as default antenna in initial process, modify it as needed */ +/* */ + +/* 3 ============================================================ */ +/* 3 SW Antenna Diversity */ +/* 3 ============================================================ */ +void odm_SwAntDivInit(struct dm_odm_t *pDM_Odm) +{ +} + +void ODM_SwAntDivChkPerPktRssi(struct dm_odm_t *pDM_Odm, u8 StationID, struct odm_phy_info *pPhyInfo) +{ +} + +void odm_SwAntDivChkAntSwitch(struct dm_odm_t *pDM_Odm, u8 Step) +{ +} + +void ODM_SwAntDivRestAfterLink(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_SwAntDivChkAntSwitchCallback23a(unsigned long data) +{ +} + +/* 3 ============================================================ */ +/* 3 SW Antenna Diversity */ +/* 3 ============================================================ */ + +void odm_InitHybridAntDiv23a(struct dm_odm_t *pDM_Odm) +{ +} + +void odm_HwAntDiv23a(struct dm_odm_t *pDM_Odm) +{ +} + +/* EDCA Turbo */ +void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm) +{ + + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; + pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false; + Adapter->recvpriv.bIsAnyNonBEPkts = false; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM))); + +} /* ODM_InitEdcaTurbo */ + +void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm) +{ + /* For AP/ADSL use struct rtl8723a_priv * */ + /* For CE/NIC use struct rtw_adapter * */ + + /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ + /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ + /* HW dynamic mechanism. */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck23a ========================>\n")); + + if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO)) + return; + + odm_EdcaTurboCheck23aCE23a(pDM_Odm); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<======================== odm_EdcaTurboCheck23a\n")); + +} /* odm_CheckEdcaTurbo */ + +void odm_EdcaTurboCheck23aCE23a(struct dm_odm_t *pDM_Odm) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + u32 trafficIndex; + u32 edca_param; + u64 cur_tx_bytes = 0; + u64 cur_rx_bytes = 0; + u8 bbtchange = false; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct xmit_priv *pxmitpriv = &Adapter->xmitpriv; + struct recv_priv *precvpriv = &Adapter->recvpriv; + struct registry_priv *pregpriv = &Adapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + if ((pregpriv->wifi_spec == 1))/* (pmlmeinfo->HT_enable == 0)) */ + goto dm_CheckEdcaTurbo_EXIT; + + if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX) + goto dm_CheckEdcaTurbo_EXIT; + +#ifdef CONFIG_8723AU_BT_COEXIST + if (BT_DisableEDCATurbo(Adapter)) + goto dm_CheckEdcaTurbo_EXIT; +#endif + + /* Check if the status needs to be changed. */ + if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) { + cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes; + cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes; + + /* traffic, TX or RX */ + if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) || + (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) { + if (cur_tx_bytes > (cur_rx_bytes << 2)) { + /* Uplink TP is present. */ + trafficIndex = UP_LINK; + } else { /* Balance TP is present. */ + trafficIndex = DOWN_LINK; + } + } else { + if (cur_rx_bytes > (cur_tx_bytes << 2)) { + /* Downlink TP is present. */ + trafficIndex = DOWN_LINK; + } else { /* Balance TP is present. */ + trafficIndex = UP_LINK; + } + } + + if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || + (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) { + if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && + (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) + edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex]; + else + edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex]; + rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); + + pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; + } + + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true; + } else { + /* Turn Off EDCA turbo here. */ + /* Restore original EDCA according to the declaration of AP. */ + if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) { + rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE); + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; + } + } + +dm_CheckEdcaTurbo_EXIT: + /* Set variables for next time. */ + precvpriv->bIsAnyNonBEPkts = false; + pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; + precvpriv->last_rx_bytes = precvpriv->rx_bytes; +} + +u32 GetPSDData(struct dm_odm_t *pDM_Odm, unsigned int point, u8 initial_gain_psd) +{ + u32 psd_report; + + /* Set DCO frequency index, offset = (40MHz/SamplePts)*point */ + ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point); + + /* Start PSD calculation, Reg808[22]= 0->1 */ + ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1); + /* Need to wait for HW PSD report */ + udelay(30); + ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0); + /* Read PSD report, Reg8B4[15:0] */ + psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF; + + psd_report = (u32)(ConvertTo_dB23a(psd_report))+(u32)(initial_gain_psd-0x1c); + + return psd_report; +} + +u32 +ConvertTo_dB23a( + u32 Value) +{ + u8 i; + u8 j; + u32 dB; + + Value = Value & 0xFFFF; + + for (i = 0; i < 8; i++) { + if (Value <= dB_Invert_Table[i][11]) + break; + } + + if (i >= 8) + return 96; /* maximum 96 dB */ + + for (j = 0; j < 12; j++) { + if (Value <= dB_Invert_Table[i][j]) + break; + } + + dB = i*12 + j + 1; + + return dB; +} + +/* */ +/* 2011/09/22 MH Add for 92D global spin lock utilization. */ +/* */ +void +odm_GlobalAdapterCheck( + void + ) +{ +} /* odm_GlobalAdapterCheck */ + +/* */ +/* Description: */ +/*Set Single/Dual Antenna default setting for products that do not do detection in advance. */ +/* */ +/* Added by Joseph, 2012.03.22 */ +/* */ +void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm) +{ + struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pDM_SWAT_Table->ANTA_ON = true; + pDM_SWAT_Table->ANTB_ON = true; +} + +/* 2 8723A ANT DETECT */ + +static void odm_PHY_SaveAFERegisters( + struct dm_odm_t *pDM_Odm, + u32 *AFEReg, + u32 *AFEBackup, + u32 RegisterNum + ) +{ + u32 i; + + /* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */ + for (i = 0 ; i < RegisterNum ; i++) + AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord); +} + +static void odm_PHY_ReloadAFERegisters(struct dm_odm_t *pDM_Odm, u32 *AFEReg, + u32 *AFEBackup, u32 RegiesterNum) +{ + u32 i; + + for (i = 0 ; i < RegiesterNum; i++) + ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]); +} + +/* 2 8723A ANT DETECT */ +/* Description: */ +/* Implement IQK single tone for RF DPK loopback and BB PSD scanning. */ +/* This function is cooperated with BB team Neil. */ +bool ODM_SingleDualAntennaDetection(struct dm_odm_t *pDM_Odm, u8 mode) +{ + struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u32 CurrentChannel, RfLoopReg; + u8 n; + u32 Reg88c, Regc08, Reg874, Regc50; + u8 initial_gain = 0x5a; + u32 PSD_report_tmp; + u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0; + bool bResult = true; + u32 AFE_Backup[16]; + u32 AFE_REG_8723A[16] = { + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN, + rFPGA0_XCD_SwitchControl, rBlue_Tooth}; + + if (!(pDM_Odm->SupportICType & (ODM_RTL8723A))) + return bResult; + + if (!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) + return bResult; + /* 1 Backup Current RF/BB Settings */ + + CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask); + RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask); + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); /* change to Antenna A */ + /* Step 1: USE IQK to transmitter single tone */ + + udelay(10); + + /* Store A Path Register 88c, c08, 874, c50 */ + Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord); + Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord); + Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord); + Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord); + + /* Store AFE Registers */ + odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); + + /* Set PSD 128 pts */ + ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0); /* 128 pts */ + + /* To SET CH1 to do */ + ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01); /* Channel 1 */ + + /* AFE all on step */ + ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4); + + /* 3 wire Disable */ + ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0); + + /* BB IQK Setting */ + ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000); + + /* IQK setting tone@ 4.34Mhz */ + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C); + ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); + + /* Page B init */ + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000); + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); + ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); + ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008); + ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0); + + /* RF loop Setting */ + ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008); + + /* IQK Single tone start */ + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + udelay(1000); + PSD_report_tmp = 0x0; + + for (n = 0; n < 2; n++) { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if (PSD_report_tmp > AntA_report) + AntA_report = PSD_report_tmp; + } + + PSD_report_tmp = 0x0; + + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); /* change to Antenna B */ + udelay(10); + + for (n = 0; n < 2; n++) { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if (PSD_report_tmp > AntB_report) + AntB_report = PSD_report_tmp; + } + + /* change to open case */ + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0); /* change to Ant A and B all open case */ + udelay(10); + + for (n = 0; n < 2; n++) { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if (PSD_report_tmp > AntO_report) + AntO_report = PSD_report_tmp; + } + + /* Close IQK Single Tone function */ + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + PSD_report_tmp = 0x0; + + /* 1 Return to antanna A */ + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); + ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c); + ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874); + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40); + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50); + ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); + ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg); + + /* Reload AFE Registers */ + odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d \n", 2416, AntA_report)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d \n", 2416, AntB_report)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d \n", 2416, AntO_report)); + + /* 2 Test Ant B based on Ant A is ON */ + if (mode == ANTTESTB) { + if (AntA_report >= 100) { + if (AntB_report > (AntA_report+1)) { + pDM_SWAT_Table->ANTB_ON = false; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); + } else { + pDM_SWAT_Table->ANTB_ON = true; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n")); + } + } else { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ + bResult = false; + } + } else if (mode == ANTTESTALL) { + /* 2 Test Ant A and B based on DPDT Open */ + if ((AntO_report >= 100) & (AntO_report < 118)) { + if (AntA_report > (AntO_report+1)) { + pDM_SWAT_Table->ANTA_ON = false; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is OFF")); + } else { + pDM_SWAT_Table->ANTA_ON = true; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is ON")); + } + + if (AntB_report > (AntO_report+2)) { + pDM_SWAT_Table->ANTB_ON = false; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is OFF")); + } else { + pDM_SWAT_Table->ANTB_ON = true; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is ON")); + } + } + } else { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTA_ON = true; /* Set Antenna A on as default */ + pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ + bResult = false; + } + return bResult; +} + +/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */ +void odm_dtc(struct dm_odm_t *pDM_Odm) +{ +} diff --git a/drivers/staging/rtl8723au/hal/odm_HWConfig.c b/drivers/staging/rtl8723au/hal/odm_HWConfig.c new file mode 100644 index 000000000000..72441709697e --- /dev/null +++ b/drivers/staging/rtl8723au/hal/odm_HWConfig.c @@ -0,0 +1,481 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 files */ +/* */ + +#include "odm_precomp.h" + +#define READ_AND_CONFIG READ_AND_CONFIG_MP + +#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(pDM_Odm)) +#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(pDM_Odm)) + +static u8 odm_QueryRxPwrPercentage(s8 AntPower) +{ + if ((AntPower <= -100) || (AntPower >= 20)) + return 0; + else if (AntPower >= 0) + return 100; + else + return 100 + AntPower; +} + +static s32 odm_SignalScaleMapping_92CSeries(struct dm_odm_t *pDM_Odm, s32 CurrSig) +{ + s32 RetSig = 0; + + if ((pDM_Odm->SupportInterface == ODM_ITRF_USB) || (pDM_Odm->SupportInterface == ODM_ITRF_SDIO)) { + if (CurrSig >= 51 && CurrSig <= 100) + RetSig = 100; + else if (CurrSig >= 41 && CurrSig <= 50) + RetSig = 80 + ((CurrSig - 40)*2); + else if (CurrSig >= 31 && CurrSig <= 40) + RetSig = 66 + (CurrSig - 30); + else if (CurrSig >= 21 && CurrSig <= 30) + RetSig = 54 + (CurrSig - 20); + else if (CurrSig >= 10 && CurrSig <= 20) + RetSig = 42 + (((CurrSig - 10) * 2) / 3); + else if (CurrSig >= 5 && CurrSig <= 9) + RetSig = 22 + (((CurrSig - 5) * 3) / 2); + else if (CurrSig >= 1 && CurrSig <= 4) + RetSig = 6 + (((CurrSig - 1) * 3) / 2); + else + RetSig = CurrSig; + } + return RetSig; +} + +static s32 odm_SignalScaleMapping(struct dm_odm_t *pDM_Odm, s32 CurrSig) +{ + return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig); +} + +static u8 +odm_EVMdbToPercentage( + s8 Value + ) +{ + /* */ + /* -33dB~0dB to 0%~99% */ + /* */ + s8 ret_val; + + ret_val = Value; + + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + + ret_val = 0 - ret_val; + ret_val *= 3; + + if (ret_val == 99) + ret_val = 100; + + return ret_val; +} + +static void odm_RxPhyStatus92CSeries_Parsing(struct dm_odm_t *pDM_Odm, + struct odm_phy_info *pPhyInfo, + u8 *pPhyStatus, + struct odm_packet_info *pPktinfo) +{ + struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus; + u8 i, Max_spatial_stream; + s8 rx_pwr[4], rx_pwr_all = 0; + u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT; + u8 RSSI, total_rssi = 0; + u8 isCCKrate = 0; + u8 rf_rx_num = 0; + u8 cck_highpwr = 0; + + isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false; + pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = -1; + pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; + + if (isCCKrate) { + u8 report; + u8 cck_agc_rpt; + + pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; + /* (1)Hardware does not provide RSSI for CCK */ + /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ + + cck_highpwr = pDM_Odm->bCckHighPower; + + cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; + + /* The RSSI formula should be modified according to the gain table */ + if (!cck_highpwr) { + report = (cck_agc_rpt & 0xc0)>>6; + switch (report) { + /* Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */ + /* Note: different RF with the different RNA gain. */ + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + report = (cck_agc_rpt & 0x60)>>5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + } + } + + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + + /* Modification for ext-LNA board */ + if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { + if ((cck_agc_rpt>>7) == 0) { + PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6); + } else { + if (PWDB_ALL > 38) + PWDB_ALL -= 16; + else + PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12); + } + + /* CCK modification */ + if (PWDB_ALL > 25 && PWDB_ALL <= 60) + PWDB_ALL += 6; + } else { /* Modification for int-LNA board */ + if (PWDB_ALL > 99) + PWDB_ALL -= 8; + else if (PWDB_ALL > 50 && PWDB_ALL <= 68) + PWDB_ALL += 4; + } + pPhyInfo->RxPWDBAll = PWDB_ALL; + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; + pPhyInfo->RecvSignalPower = rx_pwr_all; + /* (3) Get Signal Quality (EVM) */ + if (pPktinfo->bPacketMatchBSSID) { + u8 SQ, SQ_rpt; + + SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; + + if (SQ_rpt > 64) + SQ = 0; + else if (SQ_rpt < 20) + SQ = 100; + else + SQ = ((64-SQ_rpt) * 100) / 44; + + pPhyInfo->SignalQuality = SQ; + pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ; + pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; + } + } else { /* is OFDM rate */ + pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; + + /* (1)Get RSSI for HT rate */ + + for (i = RF_PATH_A; i < RF_PATH_MAX; i++) { + /* 2008/01/30 MH we will judge RF RX path now. */ + if (pDM_Odm->RFPathRxEnable & BIT(i)) + rf_rx_num++; + + rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110; + + pPhyInfo->RxPwr[i] = rx_pwr[i]; + + /* Translate DBM to percentage. */ + RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); + total_rssi += RSSI; + + /* Modification for ext-LNA board */ + if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { + if ((pPhyStaRpt->path_agc[i].trsw) == 1) + RSSI = (RSSI > 94) ? 100 : (RSSI+6); + else + RSSI = (RSSI <= 16) ? (RSSI>>3) : (RSSI-16); + + if ((RSSI <= 34) && (RSSI >= 4)) + RSSI -= 4; + } + + pPhyInfo->RxMIMOSignalStrength[i] = (u8) RSSI; + + /* Get Rx snr value in DB */ + pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); + } + + /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ + rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f)-110; + + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + PWDB_ALL_BT = PWDB_ALL; + + pPhyInfo->RxPWDBAll = PWDB_ALL; + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; + pPhyInfo->RxPower = rx_pwr_all; + pPhyInfo->RecvSignalPower = rx_pwr_all; + + /* (3)EVM of HT rate */ + if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15) + Max_spatial_stream = 2; /* both spatial stream make sense */ + else + Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ + + for (i = 0; i < Max_spatial_stream; i++) { + /* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */ + /* fill most significant bit to "zero" when doing shifting operation which may change a negative */ + /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */ + EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */ + + if (pPktinfo->bPacketMatchBSSID) { + if (i == RF_PATH_A) { + /* Fill value in RFD, Get the first spatial stream only */ + pPhyInfo->SignalQuality = (u8)(EVM & 0xff); + } + pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); + } + } + } + /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ + /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ + if (isCCKrate) { + pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ + } else { + if (rf_rx_num != 0) + pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num)); + } +} + +void odm_Init_RSSIForDM23a(struct dm_odm_t *pDM_Odm) +{ +} + +static void odm_Process_RSSIForDM(struct dm_odm_t *pDM_Odm, + struct odm_phy_info *pPhyInfo, + struct odm_packet_info *pPktinfo) +{ + s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK; + s32 UndecoratedSmoothedOFDM, RSSI_Ave; + u8 isCCKrate = 0; + u8 RSSI_max, RSSI_min, i; + u32 OFDM_pkt = 0; + u32 Weighting = 0; + struct sta_info *pEntry; + + if (pPktinfo->StationID == 0xFF) + return; + + pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; + if (!IS_STA_VALID(pEntry)) + return; + if ((!pPktinfo->bPacketMatchBSSID)) + return; + + isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false; + + /* Smart Antenna Debug Message------------------*/ + + UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; + UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; + UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; + + if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { + if (!isCCKrate) { /* ofdm rate */ + if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_B] == 0) { + RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; + } else { + if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]) { + RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; + RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; + } else { + RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; + RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; + } + if ((RSSI_max - RSSI_min) < 3) + RSSI_Ave = RSSI_max; + else if ((RSSI_max - RSSI_min) < 6) + RSSI_Ave = RSSI_max - 1; + else if ((RSSI_max - RSSI_min) < 10) + RSSI_Ave = RSSI_max - 2; + else + RSSI_Ave = RSSI_max - 3; + } + + /* 1 Process OFDM RSSI */ + if (UndecoratedSmoothedOFDM <= 0) { + /* initialize */ + UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; + } else { + if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) { + UndecoratedSmoothedOFDM = + (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + + (RSSI_Ave)) / (Rx_Smooth_Factor); + UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; + } else { + UndecoratedSmoothedOFDM = + (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + + (RSSI_Ave)) / (Rx_Smooth_Factor); + } + } + pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; + } else { + RSSI_Ave = pPhyInfo->RxPWDBAll; + + /* 1 Process CCK RSSI */ + if (UndecoratedSmoothedCCK <= 0) { + /* initialize */ + UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; + } else { + if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) { + UndecoratedSmoothedCCK = + (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + + (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor); + UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; + } else { + UndecoratedSmoothedCCK = + (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + + (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor); + } + } + pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; + } + + /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ + if (pEntry->rssi_stat.ValidBit >= 64) + pEntry->rssi_stat.ValidBit = 64; + else + pEntry->rssi_stat.ValidBit++; + + for (i = 0; i < pEntry->rssi_stat.ValidBit; i++) + OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0; + + if (pEntry->rssi_stat.ValidBit == 64) { + Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4); + UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; + } else { + if (pEntry->rssi_stat.ValidBit != 0) + UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; + else + UndecoratedSmoothedPWDB = 0; + } + pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; + pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; + pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; + } +} + +/* Endianness before calling this API */ +static void ODM_PhyStatusQuery23a_92CSeries(struct dm_odm_t *pDM_Odm, + struct odm_phy_info *pPhyInfo, + u8 *pPhyStatus, + struct odm_packet_info *pPktinfo) +{ + odm_RxPhyStatus92CSeries_Parsing(pDM_Odm, pPhyInfo, + pPhyStatus, pPktinfo); + if (pDM_Odm->RSSI_test) { + /* Select the packets to do RSSI checking for antenna switching. */ + if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) + ODM_SwAntDivChkPerPktRssi(pDM_Odm, pPktinfo->StationID, pPhyInfo); + } else { + odm_Process_RSSIForDM(pDM_Odm, pPhyInfo, pPktinfo); + } +} + +void ODM_PhyStatusQuery23a(struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, + u8 *pPhyStatus, struct odm_packet_info *pPktinfo) +{ + ODM_PhyStatusQuery23a_92CSeries(pDM_Odm, pPhyInfo, pPhyStatus, pPktinfo); +} + +/* For future use. */ +void ODM_MacStatusQuery23a(struct dm_odm_t *pDM_Odm, u8 *pMacStatus, u8 MacID, + bool bPacketMatchBSSID, bool bPacketToSelf, + bool bPacketBeacon) +{ + /* 2011/10/19 Driver team will handle in the future. */ + +} + +enum hal_status +ODM_ConfigRFWithHeaderFile23a( + struct dm_odm_t *pDM_Odm, + enum RF_RADIO_PATH Content, + enum RF_RADIO_PATH eRFPath + ) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===>ODM_ConfigRFWithHeaderFile23a\n")); + if (pDM_Odm->SupportICType == ODM_RTL8723A) { + if (eRFPath == RF_PATH_A) + READ_AND_CONFIG_MP(8723A, _RadioA_1T_); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + (" ===> ODM_ConfigRFWithHeaderFile23a() Radio_A:Rtl8723RadioA_1TArray\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + (" ===> ODM_ConfigRFWithHeaderFile23a() Radio_B:Rtl8723RadioB_1TArray\n")); + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, + ("ODM_ConfigRFWithHeaderFile23a: Radio No %x\n", eRFPath)); + return HAL_STATUS_SUCCESS; +} + +enum hal_status +ODM_ConfigBBWithHeaderFile23a( + struct dm_odm_t *pDM_Odm, + enum odm_bb_config_type ConfigType + ) +{ + if (pDM_Odm->SupportICType == ODM_RTL8723A) { + if (ConfigType == CONFIG_BB_PHY_REG) + READ_AND_CONFIG_MP(8723A, _PHY_REG_1T_); + else if (ConfigType == CONFIG_BB_AGC_TAB) + READ_AND_CONFIG_MP(8723A, _AGC_TAB_1T_); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + (" ===> phy_ConfigBBWithHeaderFile() phy:Rtl8723AGCTAB_1TArray\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8723PHY_REG_1TArray\n")); + } + return HAL_STATUS_SUCCESS; +} + +enum hal_status +ODM_ConfigMACWithHeaderFile23a( + struct dm_odm_t *pDM_Odm + ) +{ + u8 result = HAL_STATUS_SUCCESS; + + if (pDM_Odm->SupportICType == ODM_RTL8723A) + READ_AND_CONFIG_MP(8723A, _MAC_REG_); + return result; +} diff --git a/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c b/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c new file mode 100644 index 000000000000..d076e14f36b9 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 "odm_precomp.h" + +void +odm_ConfigRFReg_8723A( + struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Data, + enum RF_RADIO_PATH RF_PATH, + u32 RegAddr + ) +{ + if (Addr == 0xfe) { + msleep(50); + } else if (Addr == 0xfd) { + mdelay(5); + } else if (Addr == 0xfc) { + mdelay(1); + } else if (Addr == 0xfb) { + udelay(50); + } else if (Addr == 0xfa) { + udelay(5); + } else if (Addr == 0xf9) { + udelay(1); + } else { + ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data); + /* Add 1us delay between BB/RF register setting. */ + udelay(1); + } +} + +void odm_ConfigRF_RadioA_8723A(struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Data + ) +{ + u32 content = 0x1000; /* RF_Content: radioa_txt */ + u32 maskforPhySet = (u32)(content&0xE000); + + odm_ConfigRFReg_8723A(pDM_Odm, Addr, Data, RF_PATH_A, + Addr|maskforPhySet); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigRFWithHeaderFile23a: [RadioA] %08X %08X\n", + Addr, Data)); +} + +void odm_ConfigRF_RadioB_8723A(struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Data + ) +{ + u32 content = 0x1001; /* RF_Content: radiob_txt */ + u32 maskforPhySet = (u32)(content&0xE000); + + odm_ConfigRFReg_8723A(pDM_Odm, Addr, Data, RF_PATH_B, + Addr|maskforPhySet); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigRFWithHeaderFile23a: [RadioB] %08X %08X\n", + Addr, Data)); +} + +void odm_ConfigMAC_8723A(struct dm_odm_t *pDM_Odm, + u32 Addr, + u8 Data + ) +{ + ODM_Write1Byte(pDM_Odm, Addr, Data); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigMACWithHeaderFile23a: [MAC_REG] %08X %08X\n", + Addr, Data)); +} + +void +odm_ConfigBB_AGC_8723A( + struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Bitmask, + u32 Data + ) +{ + ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); + /* Add 1us delay between BB/RF register setting. */ + udelay(1); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigBBWithHeaderFile23a: [AGC_TAB] %08X %08X\n", + Addr, Data)); +} + +void +odm_ConfigBB_PHY_REG_PG_8723A( + struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Bitmask, + u32 Data + ) +{ + if (Addr == 0xfe) + msleep(50); + else if (Addr == 0xfd) + mdelay(5); + else if (Addr == 0xfc) + mdelay(1); + else if (Addr == 0xfb) + udelay(50); + else if (Addr == 0xfa) + udelay(5); + else if (Addr == 0xf9) + udelay(1); + /* TODO: ODM_StorePwrIndexDiffRateOffset(...) */ + /* storePwrIndexDiffRateOffset(Adapter, Addr, Bitmask, Data); */ + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigBBWithHeaderFile23a: [PHY_REG] %08X %08X %08X\n", + Addr, Bitmask, Data)); +} + +void +odm_ConfigBB_PHY_8723A( + struct dm_odm_t *pDM_Odm, + u32 Addr, + u32 Bitmask, + u32 Data + ) +{ + if (Addr == 0xfe) + msleep(50); + else if (Addr == 0xfd) + mdelay(5); + else if (Addr == 0xfc) + mdelay(1); + else if (Addr == 0xfb) + udelay(50); + else if (Addr == 0xfa) + udelay(5); + else if (Addr == 0xf9) + udelay(1); + else if (Addr == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = Data; + ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); + + /* Add 1us delay between BB/RF register setting. */ + udelay(1); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===> ODM_ConfigBBWithHeaderFile23a: [PHY_REG] %08X %08X\n", + Addr, Data)); +} diff --git a/drivers/staging/rtl8723au/hal/odm_debug.c b/drivers/staging/rtl8723au/hal/odm_debug.c new file mode 100644 index 000000000000..c912ab89bc3e --- /dev/null +++ b/drivers/staging/rtl8723au/hal/odm_debug.c @@ -0,0 +1,24 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 "odm_precomp.h" + +void ODM_InitDebugSetting23a(struct dm_odm_t *pDM_Odm) +{ + pDM_Odm->DebugLevel = ODM_DBG_TRACE; + pDM_Odm->DebugComponents = 0; +} + +u32 GlobalDebugLevel23A; diff --git a/drivers/staging/rtl8723au/hal/odm_interface.c b/drivers/staging/rtl8723au/hal/odm_interface.c new file mode 100644 index 000000000000..bef1269749d0 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/odm_interface.c @@ -0,0 +1,236 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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 files */ +/* */ + +#include "odm_precomp.h" +/* */ +/* ODM IO Relative API. */ +/* */ + +u8 ODM_Read1Byte(struct dm_odm_t *pDM_Odm, + u32 RegAddr + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return rtw_read8(Adapter, RegAddr); +} + +u16 ODM_Read2Byte(struct dm_odm_t *pDM_Odm, + u32 RegAddr + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return rtw_read16(Adapter, RegAddr); +} + +u32 ODM_Read4Byte(struct dm_odm_t *pDM_Odm, + u32 RegAddr + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return rtw_read32(Adapter, RegAddr); +} + +void ODM_Write1Byte( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u8 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + rtw_write8(Adapter, RegAddr, Data); +} + +void ODM_Write2Byte( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u16 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + rtw_write16(Adapter, RegAddr, Data); +} + +void ODM_Write4Byte( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u32 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + rtw_write32(Adapter, RegAddr, Data); + +} + +void ODM_SetMACReg( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u32 BitMask, + u32 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); +} + +u32 ODM_GetMACReg( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u32 BitMask + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return PHY_QueryBBReg(Adapter, RegAddr, BitMask); +} + +void ODM_SetBBReg( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u32 BitMask, + u32 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); +} + +u32 ODM_GetBBReg( + struct dm_odm_t *pDM_Odm, + u32 RegAddr, + u32 BitMask + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return PHY_QueryBBReg(Adapter, RegAddr, BitMask); +} + +void ODM_SetRFReg( + struct dm_odm_t *pDM_Odm, + enum RF_RADIO_PATH eRFPath, + u32 RegAddr, + u32 BitMask, + u32 Data + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data); +} + +u32 ODM_GetRFReg( + struct dm_odm_t *pDM_Odm, + enum RF_RADIO_PATH eRFPath, + u32 RegAddr, + u32 BitMask + ) +{ + struct rtw_adapter *Adapter = pDM_Odm->Adapter; + + return PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask); +} + +/* */ +/* ODM Memory relative API. */ +/* */ +void ODM_AllocateMemory( + struct dm_odm_t *pDM_Odm, + void **pPtr, + u32 length + ) +{ + *pPtr = rtw_zvmalloc(length); +} + +/* length could be ignored, used to detect memory leakage. */ +void ODM_FreeMemory( + struct dm_odm_t *pDM_Odm, + void *pPtr, + u32 length + ) +{ + rtw_vmfree(pPtr, length); +} + +/* */ +/* ODM MISC relative API. */ +/* */ +void +ODM_AcquireSpinLock( + struct dm_odm_t *pDM_Odm, + enum rt_spinlock_type type + ) +{ +} + +void ODM_ReleaseSpinLock( + struct dm_odm_t *pDM_Odm, + enum rt_spinlock_type type + ) +{ +} + +/* */ +/* Work item relative API. FOr MP driver only~! */ +/* */ +void ODM_InitializeWorkItem( + struct dm_odm_t *pDM_Odm, + void *pRtWorkItem, + RT_WORKITEM_CALL_BACK RtWorkItemCallback, + void *pContext, + const char *szID + ) +{ +} + +/* */ +/* ODM Timer relative API. */ +/* */ +void ODM_SetTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer, u32 msDelay) +{ + mod_timer(pTimer, jiffies + msecs_to_jiffies(msDelay)); /* ms */ +} + +void ODM_ReleaseTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer) +{ +} + +/* */ +/* ODM FW relative API. */ +/* */ +u32 ODM_FillH2CCmd( + u8 *pH2CBuffer, + u32 H2CBufferLen, + u32 CmdNum, + u32 *pElementID, + u32 *pCmdLen, + u8 **pCmbBuffer, + u8 *CmdStartSeq + ) +{ + return true; +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c new file mode 100644 index 000000000000..2d4135f741eb --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c @@ -0,0 +1,11304 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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 +#include +#include + +#define DIS_PS_RX_BCN + +#ifdef CONFIG_8723AU_BT_COEXIST + +u32 BTCoexDbgLevel = _bt_dbg_off_; + +#define RTPRINT(_Comp, _Level, Fmt)\ +do {\ + if ((BTCoexDbgLevel == _bt_dbg_on_)) {\ + printk Fmt;\ + } \ +} while (0) + +#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ +if ((BTCoexDbgLevel == _bt_dbg_on_)) {\ + u32 __i; \ + u8 *ptr = (u8 *)_Ptr; \ + printk printstr; \ + printk(" "); \ + for (__i = 0; __i < 6; __i++) \ + printk("%02X%s", ptr[__i], (__i == 5)?"":"-"); \ + printk("\n"); \ +} +#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ +if ((BTCoexDbgLevel == _bt_dbg_on_)) {\ + u32 __i; \ + u8 *ptr = (u8 *)_HexData; \ + printk(_TitleString); \ + for (__i = 0; __i < (u32)_HexDataLen; __i++) { \ + printk("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" ");\ + if (((__i + 1) % 16) == 0) \ + printk("\n"); \ + } \ + printk("\n"); \ +} +/* Added by Annie, 2005-11-22. */ +#define MAX_STR_LEN 64 +/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. */ +#define PRINTABLE(_ch) (_ch >= ' ' && _ch <= '~') +#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) \ + { \ + u32 __i; \ + u8 buffer[MAX_STR_LEN]; \ + u32 length = (_Len < MAX_STR_LEN) ? _Len : (MAX_STR_LEN-1);\ + memset(buffer, 0, MAX_STR_LEN); \ + memcpy(buffer, (u8 *)_Ptr, length); \ + for (__i = 0; __i < length; __i++) { \ + if (!PRINTABLE(buffer[__i])) \ + buffer[__i] = '?'; \ + } \ + buffer[length] = '\0'; \ + printk(_TitleString); \ + printk(": %d, <%s>\n", _Len, buffer); \ + } +#endif + +#define DCMD_Printf(...) +#define RT_ASSERT(...) + +#define rsprintf snprintf + +#define GetDefaultAdapter(padapter) padapter + +#define PlatformZeroMemory(ptr, sz) memset(ptr, 0, sz) + +#define PlatformProcessHCICommands(...) +#define PlatformTxBTQueuedPackets(...) +#define PlatformIndicateBTACLData(...) (RT_STATUS_SUCCESS) +#define PlatformAcquireSpinLock(padapter, type) +#define PlatformReleaseSpinLock(padapter, type) + +#define GET_UNDECORATED_AVERAGE_RSSI(padapter) \ + (GET_HAL_DATA(padapter)->dmpriv.EntryMinUndecoratedSmoothedPWDB) +#define RT_RF_CHANGE_SOURCE u32 + +enum { + RT_JOIN_INFRA = 1, + RT_JOIN_IBSS = 2, + RT_START_IBSS = 3, + RT_NO_ACTION = 4, +}; + +/* power saving */ + +#ifdef __BT_C__ /* COMMOM/BT.c */ +/* ===== Below this line is sync from SD7 driver COMMOM/BT.c ===== */ + +static u8 BT_Operation(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->BtOperationOn) + return true; + else + return false; +} + +static u8 BT_IsLegalChannel(struct rtw_adapter *padapter, u8 channel) +{ + struct rt_channel_info *pChanneList = NULL; + u8 channelLen, i; + + pChanneList = padapter->mlmeextpriv.channel_set; + channelLen = padapter->mlmeextpriv.max_chan_nums; + + for (i = 0; i < channelLen; i++) { + RTPRINT(FIOCTL, IOCTL_STATE, + ("Check if chnl(%d) in channel plan contains bt target chnl(%d) for BT connection\n", + pChanneList[i].ChannelNum, channel)); + if ((channel == pChanneList[i].ChannelNum) || + (channel == pChanneList[i].ChannelNum + 2)) + return channel; + } + return 0; +} + +void BT_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt) +{ + BTDM_SignalCompensation(padapter, rssi_wifi, rssi_bt); +} + +void BT_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType) +{ + BTHCI_WifiScanNotify(padapter, scanType); + BTDM_CheckAntSelMode(padapter); + BTDM_WifiScanNotify(padapter, scanType); +} + +void BT_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action) +{ + /* action : */ + /* true = associate start */ + /* false = associate finished */ + if (action) + BTDM_CheckAntSelMode(padapter); + + BTDM_WifiAssociateNotify(padapter, action); +} + +void BT_WifiMediaStatusNotify(struct rtw_adapter *padapter, enum rt_media_status mstatus) +{ + BTDM_MediaStatusNotify(padapter, mstatus); +} + +void BT_SpecialPacketNotify(struct rtw_adapter *padapter) +{ + BTDM_ForDhcp(padapter); +} + +void BT_HaltProcess(struct rtw_adapter *padapter) +{ + BTDM_ForHalt(padapter); +} + +void BT_LpsLeave(struct rtw_adapter *padapter) +{ + BTDM_LpsLeave(padapter); +} + +/* ===== End of sync from SD7 driver COMMOM/BT.c ===== */ +#endif + +#ifdef __BT_HANDLEPACKET_C__ /* COMMOM/bt_handlepacket.c */ +/* ===== Below this line is sync from SD7 driver COMMOM/bt_handlepacket.c ===== */ + +/* ===== End of sync from SD7 driver COMMOM/bt_handlepacket.c ===== */ +#endif + +#ifdef __BT_HCI_C__ /* COMMOM/bt_hci.c */ + +#define i64fmt "ll" +#define UINT64_C(v) (v) + +#define FillOctetString(_os, _octet, _len) \ + (_os).Octet = (u8 *)(_octet); \ + (_os).Length = (_len); + +static enum rt_status PlatformIndicateBTEvent( + struct rtw_adapter *padapter, + void *pEvntData, + u32 dataLen + ) +{ + enum rt_status rt_status = RT_STATUS_FAILURE; + + RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL, ("BT event start, %d bytes data to Transferred!!\n", dataLen)); + RTPRINT_DATA(FIOCTL, IOCTL_BT_EVENT_DETAIL, "To transfer Hex Data :\n", + pEvntData, dataLen); + + BT_EventParse(padapter, pEvntData, dataLen); + + printk(KERN_WARNING "%s: Linux has no way to report BT event!!\n", __func__); + + RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL, ("BT event end, %s\n", + (rt_status == RT_STATUS_SUCCESS) ? "SUCCESS" : "FAIL")); + + return rt_status; +} + +/* ===== Below this line is sync from SD7 driver COMMOM/bt_hci.c ===== */ + +static u8 bthci_GetLocalChannel(struct rtw_adapter *padapter) +{ + return padapter->mlmeextpriv.cur_channel; +} + +static u8 bthci_GetCurrentEntryNum(struct rtw_adapter *padapter, u8 PhyHandle) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + u8 i; + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + if ((pBTInfo->BtAsocEntry[i].bUsed) && + (pBTInfo->BtAsocEntry[i].PhyLinkCmdData.BtPhyLinkhandle == PhyHandle)) + return i; + } + + return 0xFF; +} + +static void bthci_DecideBTChannel(struct rtw_adapter *padapter, u8 EntryNum) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct mlme_priv *pmlmepriv; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_hci_info *pBtHciInfo; + struct chnl_txpower_triple *pTriple_subband = NULL; + struct common_triple *pTriple; + u8 i, j, localchnl, firstRemoteLegalChnlInTriplet = 0; + u8 regulatory_skipLen = 0; + u8 subbandTripletCnt = 0; + + pmlmepriv = &padapter->mlmepriv; + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtHciInfo = &pBTInfo->BtHciInfo; + + pBtMgnt->CheckChnlIsSuit = true; + localchnl = bthci_GetLocalChannel(padapter); + + pTriple = (struct common_triple *) + &pBtHciInfo->BTPreChnllist[COUNTRY_STR_LEN]; + + /* contains country string, len is 3 */ + for (i = 0; i < (pBtHciInfo->BtPreChnlListLen-COUNTRY_STR_LEN); i += 3, pTriple++) { + /* */ + /* check every triplet, an triplet may be */ + /* regulatory extension identifier or sub-band triplet */ + /* */ + if (pTriple->byte_1st == 0xc9) { + /* Regulatory Extension Identifier, skip it */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), + ("Find Regulatory ID, regulatory class = %d\n", pTriple->byte_2nd)); + regulatory_skipLen += 3; + pTriple_subband = NULL; + continue; + } else { /* Sub-band triplet */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Find Sub-band triplet \n")); + subbandTripletCnt++; + pTriple_subband = (struct chnl_txpower_triple *)pTriple; + /* if remote first legal channel not found, then find first remote channel */ + /* and it's legal for our channel plan. */ + + /* search the sub-band triplet and find if remote channel is legal to our channel plan. */ + for (j = pTriple_subband->FirstChnl; j < (pTriple_subband->FirstChnl+pTriple_subband->NumChnls); j++) { + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), (" Check if chnl(%d) is legal\n", j)); + if (BT_IsLegalChannel(padapter, j)) { + /* remote channel is legal for our channel plan. */ + firstRemoteLegalChnlInTriplet = j; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), + ("Find first remote legal channel : %d\n", + firstRemoteLegalChnlInTriplet)); + + /* If we find a remote legal channel in the sub-band triplet */ + /* and only BT connection is established(local not connect to any AP or IBSS), */ + /* then we just switch channel to remote channel. */ + if (!(check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_ADHOC_STATE|WIFI_AP_STATE) || + BTHCI_HsConnectionEstablished(padapter))) { + pBtMgnt->BTChannel = firstRemoteLegalChnlInTriplet; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Remote legal channel (%d) is selected, Local not connect to any!!\n", pBtMgnt->BTChannel)); + return; + } else { + if ((localchnl >= firstRemoteLegalChnlInTriplet) && + (localchnl < (pTriple_subband->FirstChnl+pTriple_subband->NumChnls))) { + pBtMgnt->BTChannel = localchnl; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Local channel (%d) is selected, wifi or BT connection exists\n", pBtMgnt->BTChannel)); + return; + } + } + break; + } + } + } + } + + if (subbandTripletCnt) { + /* if any preferred channel triplet exists */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("There are %d sub band triplet exists, ", subbandTripletCnt)); + if (firstRemoteLegalChnlInTriplet == 0) { + /* no legal channel is found, reject the connection. */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("no legal channel is found!!\n")); + } else { + /* Remote Legal channel is found but not match to local */ + /* wifi connection exists), so reject the connection. */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), + ("Remote Legal channel is found but not match to local(wifi connection exists)!!\n")); + } + pBtMgnt->CheckChnlIsSuit = false; + } else { + /* There are not any preferred channel triplet exists */ + /* Use current legal channel as the bt channel. */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("No sub band triplet exists!!\n")); + } + pBtMgnt->BTChannel = localchnl; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Local channel (%d) is selected!!\n", pBtMgnt->BTChannel)); +} + +/* Success:return true */ +/* Fail:return false */ +static u8 bthci_GetAssocInfo(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTInfo; + struct bt_hci_info *pBtHciInfo; + u8 tempBuf[256]; + u8 i = 0; + u8 BaseMemoryShift = 0; + u16 TotalLen = 0; + struct amp_assoc_structure *pAmpAsoc; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("GetAssocInfo start\n")); + pBTInfo = GET_BT_INFO(padapter); + pBtHciInfo = &pBTInfo->BtHciInfo; + + if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar == 0) { + if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen < (MAX_AMP_ASSOC_FRAG_LEN)) + TotalLen = pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen; + else if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen == (MAX_AMP_ASSOC_FRAG_LEN)) + TotalLen = MAX_AMP_ASSOC_FRAG_LEN; + } else if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar > 0) + TotalLen = pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar; + + while ((pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar >= BaseMemoryShift) || TotalLen > BaseMemoryShift) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("GetAssocInfo, TotalLen =%d, BaseMemoryShift =%d\n", TotalLen, BaseMemoryShift)); + memcpy(tempBuf, + (u8 *)pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment+BaseMemoryShift, + TotalLen-BaseMemoryShift); + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, "GetAssocInfo :\n", + tempBuf, TotalLen-BaseMemoryShift); + + pAmpAsoc = (struct amp_assoc_structure *)tempBuf; + pAmpAsoc->Length = le16_to_cpu(pAmpAsoc->Length); + BaseMemoryShift += 3 + pAmpAsoc->Length; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("TypeID = 0x%x, ", pAmpAsoc->TypeID)); + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, "Hex Data: \n", pAmpAsoc->Data, pAmpAsoc->Length); + switch (pAmpAsoc->TypeID) { + case AMP_MAC_ADDR: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_MAC_ADDR\n")); + if (pAmpAsoc->Length > 6) + return false; + memcpy(pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr, pAmpAsoc->Data, 6); + RTPRINT_ADDR(FIOCTL, IOCTL_BT_HCICMD, ("Remote Mac address \n"), pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr); + break; + case AMP_PREFERRED_CHANNEL_LIST: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_PREFERRED_CHANNEL_LIST\n")); + pBtHciInfo->BtPreChnlListLen = pAmpAsoc->Length; + memcpy(pBtHciInfo->BTPreChnllist, + pAmpAsoc->Data, + pBtHciInfo->BtPreChnlListLen); + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, "Preferred channel list : \n", pBtHciInfo->BTPreChnllist, pBtHciInfo->BtPreChnlListLen); + bthci_DecideBTChannel(padapter, EntryNum); + break; + case AMP_CONNECTED_CHANNEL: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_CONNECTED_CHANNEL\n")); + pBtHciInfo->BTConnectChnlListLen = pAmpAsoc->Length; + memcpy(pBtHciInfo->BTConnectChnllist, + pAmpAsoc->Data, + pBtHciInfo->BTConnectChnlListLen); + break; + case AMP_80211_PAL_CAP_LIST: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_80211_PAL_CAP_LIST\n")); + pBTInfo->BtAsocEntry[EntryNum].BTCapability = *(u32 *)(pAmpAsoc->Data); + if (pBTInfo->BtAsocEntry[EntryNum].BTCapability & 0x00000001) { + /* TODO: */ + + /* Signifies PAL capable of utilizing received activity reports. */ + } + if (pBTInfo->BtAsocEntry[EntryNum].BTCapability & 0x00000002) { + /* TODO: */ + /* Signifies PAL is capable of utilizing scheduling information received in an activity reports. */ + } + break; + case AMP_80211_PAL_VISION: + pBtHciInfo->BTPalVersion = *(u8 *)(pAmpAsoc->Data); + pBtHciInfo->BTPalCompanyID = *(u16 *)(((u8 *)(pAmpAsoc->Data))+1); + pBtHciInfo->BTPalsubversion = *(u16 *)(((u8 *)(pAmpAsoc->Data))+3); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("==> AMP_80211_PAL_VISION PalVersion 0x%x, PalCompanyID 0x%x, Palsubversion 0x%x\n", + pBtHciInfo->BTPalVersion, + pBtHciInfo->BTPalCompanyID, + pBtHciInfo->BTPalsubversion)); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> Unsupport TypeID !!\n")); + break; + } + i++; + } + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("GetAssocInfo end\n")); + + return true; +} + +static u8 bthci_AddEntry(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + u8 i; + + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + if (pBTInfo->BtAsocEntry[i].bUsed == false) { + pBTInfo->BtAsocEntry[i].bUsed = true; + pBtMgnt->CurrentConnectEntryNum = i; + break; + } + } + + if (i == MAX_BT_ASOC_ENTRY_NUM) { + RTPRINT(FIOCTL, IOCTL_STATE, ("bthci_AddEntry(), Add entry fail!!\n")); + return false; + } + return true; +} + +static u8 bthci_DiscardTxPackets(struct rtw_adapter *padapter, u16 LLH) +{ + return false; +} + +static u8 +bthci_CheckLogLinkBehavior( + struct rtw_adapter *padapter, + struct hci_flow_spec TxFlowSpec + ) +{ + u8 ID = TxFlowSpec.Identifier; + u8 ServiceType = TxFlowSpec.ServiceType; + u16 MaxSDUSize = TxFlowSpec.MaximumSDUSize; + u32 SDUInterArrivatime = TxFlowSpec.SDUInterArrivalTime; + u8 match = false; + + switch (ID) { + case 1: + if (ServiceType == BT_LL_BE) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = TX best effort flowspec\n")); + } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 0xffff)) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = RX guaranteed latency flowspec\n")); + } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 2500)) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = RX guaranteed Large latency flowspec\n")); + } + break; + case 2: + if (ServiceType == BT_LL_BE) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = RX best effort flowspec\n")); + + } + break; + case 3: + if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 1492)) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = TX guaranteed latency flowspec\n")); + } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 2500)) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = TX guaranteed Large latency flowspec\n")); + } + break; + case 4: + if (ServiceType == BT_LL_BE) { + if ((SDUInterArrivatime == 0xffffffff) && (ServiceType == BT_LL_BE) && (MaxSDUSize == 1492)) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = TX/RX aggregated best effort flowspec\n")); + } + } else if (ServiceType == BT_LL_GU) { + if (SDUInterArrivatime == 100) { + match = true; + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = TX/RX guaranteed bandwidth flowspec\n")); + } + } + break; + default: + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type = Unknow Type !!!!!!!!\n")); + break; + } + + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), + ("ID = 0x%x, ServiceType = 0x%x, MaximumSDUSize = 0x%x, SDUInterArrivalTime = 0x%x, AccessLatency = 0x%x, FlushTimeout = 0x%x\n", + TxFlowSpec.Identifier, TxFlowSpec.ServiceType, MaxSDUSize, + SDUInterArrivatime, TxFlowSpec.AccessLatency, TxFlowSpec.FlushTimeout)); + return match; +} + +static u16 bthci_AssocMACAddr(struct rtw_adapter *padapter, void *pbuf) +{ + struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf; + pAssoStrc->TypeID = AMP_MAC_ADDR; + pAssoStrc->Length = 0x06; + memcpy(&pAssoStrc->Data[0], padapter->eeprompriv.mac_addr, 6); + RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), + ("AssocMACAddr : \n"), pAssoStrc, pAssoStrc->Length+3); + + return pAssoStrc->Length + 3; +} + +static u16 +bthci_PALCapabilities( + struct rtw_adapter *padapter, + void *pbuf + ) +{ + struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf; + + pAssoStrc->TypeID = AMP_80211_PAL_CAP_LIST; + pAssoStrc->Length = 0x04; + + pAssoStrc->Data[0] = 0x00; + pAssoStrc->Data[1] = 0x00; + + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("PALCapabilities:\n"), pAssoStrc, pAssoStrc->Length+3); + RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("PALCapabilities \n")); + + RTPRINT(FIOCTL, IOCTL_BT_LOGO, (" TypeID = 0x%x,\n Length = 0x%x,\n Content = 0x0000\n", + pAssoStrc->TypeID, + pAssoStrc->Length)); + + return pAssoStrc->Length + 3; +} + +static u16 bthci_AssocPreferredChannelList(struct rtw_adapter *padapter, + void *pbuf, u8 EntryNum) +{ + struct bt_30info *pBTInfo; + struct amp_assoc_structure *pAssoStrc; + struct amp_pref_chnl_regulatory *pReg; + struct chnl_txpower_triple *pTriple; + char ctrString[3] = {'X', 'X', 'X'}; + u32 len = 0; + u8 preferredChnl; + + pBTInfo = GET_BT_INFO(padapter); + pAssoStrc = (struct amp_assoc_structure *)pbuf; + pReg = (struct amp_pref_chnl_regulatory *)&pAssoStrc->Data[3]; + + preferredChnl = bthci_GetLocalChannel(padapter); + pAssoStrc->TypeID = AMP_PREFERRED_CHANNEL_LIST; + + /* locale unknown */ + memcpy(&pAssoStrc->Data[0], &ctrString[0], 3); + pReg->reXId = 201; + pReg->regulatoryClass = 254; + pReg->coverageClass = 0; + len += 6; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("PREFERRED_CHNL_LIST\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("XXX, 201, 254, 0\n")); + /* at the following, chnl 1~11 should be contained */ + pTriple = (struct chnl_txpower_triple *)&pAssoStrc->Data[len]; + + /* (1) if any wifi or bt HS connection exists */ + if ((pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_CREATOR) || + (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE | + WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | + WIFI_AP_STATE)) || + BTHCI_HsConnectionEstablished(padapter)) { + pTriple->FirstChnl = preferredChnl; + pTriple->NumChnls = 1; + pTriple->MaxTxPowerInDbm = 20; + len += 3; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("First Channel = %d, Channel Num = %d, MaxDbm = %d\n", + pTriple->FirstChnl, + pTriple->NumChnls, + pTriple->MaxTxPowerInDbm)); + } + + pAssoStrc->Length = (u16)len; + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, ("AssocPreferredChannelList : \n"), pAssoStrc, pAssoStrc->Length+3); + + return pAssoStrc->Length + 3; +} + +static u16 bthci_AssocPALVer(struct rtw_adapter *padapter, void *pbuf) +{ + struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf; + u8 *pu1Tmp; + u16 *pu2Tmp; + + pAssoStrc->TypeID = AMP_80211_PAL_VISION; + pAssoStrc->Length = 0x5; + pu1Tmp = &pAssoStrc->Data[0]; + *pu1Tmp = 0x1; /* PAL Version */ + pu2Tmp = (u16 *)&pAssoStrc->Data[1]; + *pu2Tmp = 0x5D; /* SIG Company identifier of 802.11 PAL vendor */ + pu2Tmp = (u16 *)&pAssoStrc->Data[3]; + *pu2Tmp = 0x1; /* PAL Sub-version specifier */ + + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("AssocPALVer : \n"), pAssoStrc, pAssoStrc->Length+3); + RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("AssocPALVer \n")); + + RTPRINT(FIOCTL, IOCTL_BT_LOGO, (" TypeID = 0x%x,\n Length = 0x%x,\n PAL Version = 0x01,\n PAL vendor = 0x01,\n PAL Sub-version specifier = 0x01\n", + pAssoStrc->TypeID, + pAssoStrc->Length)); + return pAssoStrc->Length + 3; +} + +static u8 bthci_CheckRfStateBeforeConnect(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo; + enum rt_rf_power_state RfState; + + pBTInfo = GET_BT_INFO(padapter); + + RfState = padapter->pwrctrlpriv.rf_pwrstate; + + if (RfState != rf_on) { + mod_timer(&pBTInfo->BTPsDisableTimer, + jiffies + msecs_to_jiffies(50)); + return false; + } + return true; +} + +static void bthci_ResponderStartToScan(struct rtw_adapter *padapter) +{ +} + +static u8 bthci_PhyLinkConnectionInProgress(struct rtw_adapter *padapter, u8 PhyLinkHandle) +{ + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->bPhyLinkInProgress && + (pBtMgnt->BtCurrentPhyLinkhandle == PhyLinkHandle)) + return true; + return false; +} + +static void bthci_ResetFlowSpec(struct rtw_adapter *padapter, u8 EntryNum, u8 index) +{ + struct bt_30info *pBTinfo; + + pBTinfo = GET_BT_INFO(padapter); + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtLogLinkhandle = 0; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtPhyLinkhandle = 0; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].bLLCompleteEventIsSet = false; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].bLLCancelCMDIsSetandComplete = false; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtTxFlowSpecID = 0; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].TxPacketCount = 0; + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.Identifier = 0x01; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.ServiceType = SERVICE_BEST_EFFORT; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.MaximumSDUSize = 0xffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.SDUInterArrivalTime = 0xffffffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.AccessLatency = 0xffffffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.FlushTimeout = 0xffffffff; + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.Identifier = 0x01; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.ServiceType = SERVICE_BEST_EFFORT; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.MaximumSDUSize = 0xffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.SDUInterArrivalTime = 0xffffffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.AccessLatency = 0xffffffff; + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.FlushTimeout = 0xffffffff; +} + +static void bthci_ResetEntry(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTinfo; + struct bt_mgnt *pBtMgnt; + u8 j; + + pBTinfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTinfo->BtMgnt; + + pBTinfo->BtAsocEntry[EntryNum].bUsed = false; + pBTinfo->BtAsocEntry[EntryNum].BtCurrentState = HCI_STATE_DISCONNECTED; + pBTinfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED; + + pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen = 0; + pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.BtPhyLinkhandle = 0; + if (pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment != NULL) + memset(pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment, 0, TOTAL_ALLOCIATE_ASSOC_LEN); + pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar = 0; + + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType = 0; + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle = 0; + memset(pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, 0, + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen); + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen = 0; + + /* 0x640; 0.625ms*1600 = 1000ms, 0.625ms*16000 = 10000ms */ + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout = 0x3e80; + + pBTinfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_NONE; + + pBTinfo->BtAsocEntry[EntryNum].mAssoc = false; + pBTinfo->BtAsocEntry[EntryNum].b4waySuccess = false; + + /* Reset BT WPA */ + pBTinfo->BtAsocEntry[EntryNum].KeyReplayCounter = 0; + pBTinfo->BtAsocEntry[EntryNum].BTWPAAuthState = STATE_WPA_AUTH_UNINITIALIZED; + + pBTinfo->BtAsocEntry[EntryNum].bSendSupervisionPacket = false; + pBTinfo->BtAsocEntry[EntryNum].NoRxPktCnt = 0; + pBTinfo->BtAsocEntry[EntryNum].ShortRangeMode = 0; + pBTinfo->BtAsocEntry[EntryNum].rxSuvpPktCnt = 0; + + for (j = 0; j < MAX_LOGICAL_LINK_NUM; j++) + bthci_ResetFlowSpec(padapter, EntryNum, j); + + pBtMgnt->BTAuthCount = 0; + pBtMgnt->BTAsocCount = 0; + pBtMgnt->BTCurrentConnectType = BT_DISCONNECT; + pBtMgnt->BTReceiveConnectPkt = BT_DISCONNECT; + + HALBT_RemoveKey(padapter, EntryNum); +} + +static void bthci_RemoveEntryByEntryNum(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + bthci_ResetEntry(padapter, EntryNum); + + if (pBtMgnt->CurrentBTConnectionCnt > 0) + pBtMgnt->CurrentBTConnectionCnt--; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], CurrentBTConnectionCnt = %d!!\n", + pBtMgnt->CurrentBTConnectionCnt)); + + if (pBtMgnt->CurrentBTConnectionCnt > 0) { + pBtMgnt->BtOperationOn = true; + } else { + pBtMgnt->BtOperationOn = false; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], Bt Operation OFF!!\n")); + } + + if (!pBtMgnt->BtOperationOn) { + del_timer_sync(&pBTInfo->BTHCIDiscardAclDataTimer); + del_timer_sync(&pBTInfo->BTBeaconTimer); + pBtMgnt->bStartSendSupervisionPkt = false; + } +} + +static u8 +bthci_CommandCompleteHeader( + u8 *pbuf, + u16 OGF, + u16 OCF, + enum hci_status status + ) +{ + struct packet_irp_hcievent_data *PPacketIrpEvent = (struct packet_irp_hcievent_data *)pbuf; + u8 NumHCI_Comm = 0x1; + + PPacketIrpEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + PPacketIrpEvent->Data[0] = NumHCI_Comm; /* packet # */ + PPacketIrpEvent->Data[1] = HCIOPCODELOW(OCF, OGF); + PPacketIrpEvent->Data[2] = HCIOPCODEHIGHT(OCF, OGF); + + if (OGF == OGF_EXTENSION) { + if (OCF == HCI_SET_RSSI_VALUE) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT_PERIODICAL), + ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n", + NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF)); + } else { + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_EXT), + ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n", + NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF)); + } + } else { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), + ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n", + NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF)); + } + return 3; +} + +static u8 bthci_ExtensionEventHeaderRtk(u8 *pbuf, u8 extensionEvent) +{ + struct packet_irp_hcievent_data *PPacketIrpEvent = (struct packet_irp_hcievent_data *)pbuf; + PPacketIrpEvent->EventCode = HCI_EVENT_EXTENSION_RTK; + PPacketIrpEvent->Data[0] = extensionEvent; /* extension event code */ + + return 1; +} + +static enum rt_status +bthci_IndicateEvent( + struct rtw_adapter *padapter, + void *pEvntData, + u32 dataLen + ) +{ + enum rt_status rt_status; + + rt_status = PlatformIndicateBTEvent(padapter, pEvntData, dataLen); + + return rt_status; +} + +static void +bthci_EventWriteRemoteAmpAssoc( + struct rtw_adapter *padapter, + enum hci_status status, + u8 PLHandle + ) +{ + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_WRITE_REMOTE_AMP_ASSOC, + status); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("PhyLinkHandle = 0x%x, status = %d\n", PLHandle, status)); + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = PLHandle; + len += 2; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); +} + +static void +bthci_EventEnhancedFlushComplete( + struct rtw_adapter *padapter, + u16 LLH + ) +{ + u8 localBuf[4] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("EventEnhancedFlushComplete, LLH = 0x%x\n", LLH)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_ENHANCED_FLUSH_COMPLETE; + PPacketIrpEvent->Length = 2; + /* Logical link handle */ + PPacketIrpEvent->Data[0] = TWOBYTE_LOWBYTE(LLH); + PPacketIrpEvent->Data[1] = TWOBYTE_HIGHTBYTE(LLH); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); +} + +static void +bthci_EventShortRangeModeChangeComplete( + struct rtw_adapter *padapter, + enum hci_status HciStatus, + u8 ShortRangeState, + u8 EntryNum + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[5] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Short Range Mode Change Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Short Range Mode Change Complete, Status = %d\n , PLH = 0x%x\n, Short_Range_Mode_State = 0x%x\n", + HciStatus, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, ShortRangeState)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE; + PPacketIrpEvent->Length = 3; + PPacketIrpEvent->Data[0] = HciStatus; + PPacketIrpEvent->Data[1] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + PPacketIrpEvent->Data[2] = ShortRangeState; + bthci_IndicateEvent(padapter, PPacketIrpEvent, 5); +} + +static void bthci_EventSendFlowSpecModifyComplete(struct rtw_adapter *padapter, + enum hci_status HciStatus, + u16 logicHandle) +{ + u8 localBuf[5] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE)) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), + ("[BT event], Flow Spec Modify Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), + ("[BT event], Flow Spec Modify Complete, status = 0x%x, LLH = 0x%x\n", HciStatus, logicHandle)); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE; + PPacketIrpEvent->Length = 3; + + PPacketIrpEvent->Data[0] = HciStatus; + /* Logical link handle */ + PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(logicHandle); + PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(logicHandle); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 5); +} + +static void +bthci_EventExtWifiScanNotify( + struct rtw_adapter *padapter, + u8 scanType + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 len = 0; + u8 localBuf[7] = ""; + u8 *pRetPar; + u8 *pu1Temp; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!pBtMgnt->BtOperationOn) + return; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_ExtensionEventHeaderRtk(&localBuf[0], HCI_EVENT_EXT_WIFI_SCAN_NOTIFY); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pu1Temp = (u8 *)&pRetPar[0]; + *pu1Temp = scanType; + len += 1; + + PPacketIrpEvent->Length = len; + + if (bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2) == RT_STATUS_SUCCESS) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Wifi scan notify, scan type = %d\n", + scanType)); + } +} + +static void +bthci_EventAMPReceiverReport( + struct rtw_adapter *padapter, + u8 Reason + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + + if (pBtHciInfo->bTestNeedReport) { + u8 localBuf[20] = ""; + u32 *pu4Temp; + u16 *pu2Temp; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), (" HCI_EVENT_AMP_RECEIVER_REPORT\n")); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_AMP_RECEIVER_REPORT; + PPacketIrpEvent->Length = 2; + + PPacketIrpEvent->Data[0] = pBtHciInfo->TestCtrType; + + PPacketIrpEvent->Data[1] = Reason; + + pu4Temp = (u32 *)&PPacketIrpEvent->Data[2]; + *pu4Temp = pBtHciInfo->TestEventType; + + pu2Temp = (u16 *)&PPacketIrpEvent->Data[6]; + *pu2Temp = pBtHciInfo->TestNumOfFrame; + + pu2Temp = (u16 *)&PPacketIrpEvent->Data[8]; + *pu2Temp = pBtHciInfo->TestNumOfErrFrame; + + pu4Temp = (u32 *)&PPacketIrpEvent->Data[10]; + *pu4Temp = pBtHciInfo->TestNumOfBits; + + pu4Temp = (u32 *)&PPacketIrpEvent->Data[14]; + *pu4Temp = pBtHciInfo->TestNumOfErrBits; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 20); + + /* Return to Idel state with RX and TX off. */ + + } + + pBtHciInfo->TestNumOfFrame = 0x00; +} + +static void +bthci_EventChannelSelected( + struct rtw_adapter *padapter, + u8 EntryNum + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[3] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_CHANNEL_SELECT)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Channel Selected, Ignore to send this event due to event mask page 2\n")); + return; + } + + RTPRINT(FIOCTL, IOCTL_BT_EVENT|IOCTL_STATE, + ("[BT event], Channel Selected, PhyLinkHandle %d\n", + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_CHANNEL_SELECT; + PPacketIrpEvent->Length = 1; + PPacketIrpEvent->Data[0] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + bthci_IndicateEvent(padapter, PPacketIrpEvent, 3); +} + +static void +bthci_EventDisconnectPhyLinkComplete( + struct rtw_adapter *padapter, + enum hci_status HciStatus, + enum hci_status Reason, + u8 EntryNum + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[5] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Disconnect Physical Link Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Disconnect Physical Link Complete, Status = 0x%x, PLH = 0x%x Reason = 0x%x\n", + HciStatus, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, Reason)); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE; + PPacketIrpEvent->Length = 3; + PPacketIrpEvent->Data[0] = HciStatus; + PPacketIrpEvent->Data[1] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + PPacketIrpEvent->Data[2] = Reason; + bthci_IndicateEvent(padapter, PPacketIrpEvent, 5); +} + +static void +bthci_EventPhysicalLinkComplete( + struct rtw_adapter *padapter, + enum hci_status HciStatus, + u8 EntryNum, + u8 PLHandle + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 localBuf[4] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u8 PL_handle; + + pBtMgnt->bPhyLinkInProgress = false; + pBtDbg->dbgHciInfo.hciCmdPhyLinkStatus = HciStatus; + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_PHY_LINK_COMPLETE)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Physical Link Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + + if (EntryNum == 0xff) { + /* connection not started yet, just use the input physical link handle to response. */ + PL_handle = PLHandle; + } else { + /* connection is under progress, use the phy link handle we recorded. */ + PL_handle = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent = false; + } + + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Physical Link Complete, Status = 0x%x PhyLinkHandle = 0x%x\n", HciStatus, + PL_handle)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_PHY_LINK_COMPLETE; + PPacketIrpEvent->Length = 2; + + PPacketIrpEvent->Data[0] = HciStatus; + PPacketIrpEvent->Data[1] = PL_handle; + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); + +} + +static void +bthci_EventCommandStatus( + struct rtw_adapter *padapter, + u8 OGF, + u16 OCF, + enum hci_status HciStatus + ) +{ + + u8 localBuf[6] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u8 Num_Hci_Comm = 0x1; + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], CommandStatus, Opcode = 0x%02x%02x, OGF = 0x%x, OCF = 0x%x, Status = 0x%x, Num_HCI_COMM = 0x%x\n", + (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), OGF, OCF, HciStatus, Num_Hci_Comm)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_COMMAND_STATUS; + PPacketIrpEvent->Length = 4; + PPacketIrpEvent->Data[0] = HciStatus; /* current pending */ + PPacketIrpEvent->Data[1] = Num_Hci_Comm; /* packet # */ + PPacketIrpEvent->Data[2] = HCIOPCODELOW(OCF, OGF); + PPacketIrpEvent->Data[3] = HCIOPCODEHIGHT(OCF, OGF); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 6); + +} + +static void +bthci_EventLogicalLinkComplete( + struct rtw_adapter *padapter, + enum hci_status HciStatus, + u8 PhyLinkHandle, + u16 LogLinkHandle, + u8 LogLinkIndex, + u8 EntryNum + ) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[7] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_LOGICAL_LINK_COMPLETE)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, + ("[BT event], Logical Link Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Logical Link Complete, PhyLinkHandle = 0x%x, LogLinkHandle = 0x%x, Status = 0x%x\n", + PhyLinkHandle, LogLinkHandle, HciStatus)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_LOGICAL_LINK_COMPLETE; + PPacketIrpEvent->Length = 5; + + PPacketIrpEvent->Data[0] = HciStatus;/* status code */ + /* Logical link handle */ + PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(LogLinkHandle); + PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(LogLinkHandle); + /* Physical link handle */ + PPacketIrpEvent->Data[3] = TWOBYTE_LOWBYTE(PhyLinkHandle); + /* corresponding Tx flow spec ID */ + if (HciStatus == HCI_STATUS_SUCCESS) { + PPacketIrpEvent->Data[4] = + pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData[LogLinkIndex].Tx_Flow_Spec.Identifier; + } else { + PPacketIrpEvent->Data[4] = 0x0; + } + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 7); +} + +static void +bthci_EventDisconnectLogicalLinkComplete( + struct rtw_adapter *padapter, + enum hci_status HciStatus, + u16 LogLinkHandle, + enum hci_status Reason + ) +{ + u8 localBuf[6] = ""; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Disconnect Logical Link Complete, Ignore to send this event due to event mask page 2\n")); + return; + } + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Disconnect Logical Link Complete, Status = 0x%x, LLH = 0x%x Reason = 0x%x\n", HciStatus, LogLinkHandle, Reason)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE; + PPacketIrpEvent->Length = 4; + + PPacketIrpEvent->Data[0] = HciStatus; + /* Logical link handle */ + PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(LogLinkHandle); + PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(LogLinkHandle); + /* Disconnect reason */ + PPacketIrpEvent->Data[3] = Reason; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 6); +} + +static void +bthci_EventFlushOccurred( + struct rtw_adapter *padapter, + u16 LogLinkHandle + ) +{ + u8 localBuf[4] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("bthci_EventFlushOccurred(), LLH = 0x%x\n", LogLinkHandle)); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_FLUSH_OCCRUED; + PPacketIrpEvent->Length = 2; + /* Logical link handle */ + PPacketIrpEvent->Data[0] = TWOBYTE_LOWBYTE(LogLinkHandle); + PPacketIrpEvent->Data[1] = TWOBYTE_HIGHTBYTE(LogLinkHandle); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); +} + +static enum hci_status +bthci_BuildPhysicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd, + u16 OCF +) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 EntryNum, PLH; + + /* Send HCI Command status event to AMP. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + OCF, + HCI_STATUS_SUCCESS); + + PLH = *((u8 *)pHciCmd->Data); + + /* Check if resource or bt connection is under progress, if yes, reject the link creation. */ + if (!bthci_AddEntry(padapter)) { + status = HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE; + bthci_EventPhysicalLinkComplete(padapter, status, INVALID_ENTRY_NUM, PLH); + return status; + } + + EntryNum = pBtMgnt->CurrentConnectEntryNum; + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle = PLH; + pBtMgnt->BtCurrentPhyLinkhandle = PLH; + + if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment == NULL) { + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Create/Accept PhysicalLink, AMP controller is busy\n")); + status = HCI_STATUS_CONTROLLER_BUSY; + bthci_EventPhysicalLinkComplete(padapter, status, INVALID_ENTRY_NUM, PLH); + return status; + } + + /* Record Key and the info */ + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen = (*((u8 *)pHciCmd->Data+1)); + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType = (*((u8 *)pHciCmd->Data+2)); + memcpy(pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, + (((u8 *)pHciCmd->Data+3)), pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen); + memcpy(pBTInfo->BtAsocEntry[EntryNum].PMK, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, PMK_LEN); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("BuildPhysicalLink, EntryNum = %d, PLH = 0x%x KeyLen = 0x%x, KeyType = 0x%x\n", + EntryNum, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType)); + RTPRINT_DATA(FIOCTL, (IOCTL_BT_LOGO|IOCTL_BT_HCICMD), ("BtAMPKey\n"), pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen); + RTPRINT_DATA(FIOCTL, (IOCTL_BT_LOGO|IOCTL_BT_HCICMD), ("PMK\n"), pBTInfo->BtAsocEntry[EntryNum].PMK, + PMK_LEN); + + if (OCF == HCI_CREATE_PHYSICAL_LINK) { + /* These macros require braces */ + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_CREATE_PHY_LINK, EntryNum); + } else if (OCF == HCI_ACCEPT_PHYSICAL_LINK) { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ACCEPT_PHY_LINK, EntryNum); + } + + return status; +} + +static void +bthci_BuildLogicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd, + u16 OCF + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt; + u8 PhyLinkHandle, EntryNum; + static u16 AssignLogHandle = 1; + + struct hci_flow_spec TxFlowSpec; + struct hci_flow_spec RxFlowSpec; + u32 MaxSDUSize, ArriveTime, Bandwidth; + + PhyLinkHandle = *((u8 *)pHciCmd->Data); + + EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle); + + memcpy(&TxFlowSpec, + &pHciCmd->Data[1], sizeof(struct hci_flow_spec)); + memcpy(&RxFlowSpec, + &pHciCmd->Data[17], sizeof(struct hci_flow_spec)); + + MaxSDUSize = TxFlowSpec.MaximumSDUSize; + ArriveTime = TxFlowSpec.SDUInterArrivalTime; + + if (bthci_CheckLogLinkBehavior(padapter, TxFlowSpec) && bthci_CheckLogLinkBehavior(padapter, RxFlowSpec)) + Bandwidth = BTTOTALBANDWIDTH; + else if (MaxSDUSize == 0xffff && ArriveTime == 0xffffffff) + Bandwidth = BTTOTALBANDWIDTH; + else + Bandwidth = MaxSDUSize*8*1000/(ArriveTime+244); + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, + ("BuildLogicalLink, PhyLinkHandle = 0x%x, MaximumSDUSize = 0x%x, SDUInterArrivalTime = 0x%x, Bandwidth = 0x%x\n", + PhyLinkHandle, MaxSDUSize, ArriveTime, Bandwidth)); + + if (EntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Invalid Physical Link handle = 0x%x, status = HCI_STATUS_UNKNOW_CONNECT_ID, return\n", PhyLinkHandle)); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + /* When we receive Create/Accept logical link command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + OCF, + status); + return; + } + + if (!pBtMgnt->bLogLinkInProgress) { + if (bthci_PhyLinkConnectionInProgress(padapter, PhyLinkHandle)) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Physical link connection in progress, status = HCI_STATUS_CMD_DISALLOW, return\n")); + status = HCI_STATUS_CMD_DISALLOW; + + pBtMgnt->bPhyLinkInProgressStartLL = true; + /* When we receive Create/Accept logical link command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + OCF, + status); + + return; + } + + if (Bandwidth > BTTOTALBANDWIDTH) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("status = HCI_STATUS_QOS_REJECT, Bandwidth = 0x%x, return\n", Bandwidth)); + status = HCI_STATUS_QOS_REJECT; + + /* When we receive Create/Accept logical link command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + OCF, + status); + } else { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("status = HCI_STATUS_SUCCESS\n")); + status = HCI_STATUS_SUCCESS; + + /* When we receive Create/Accept logical link command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + OCF, + status); + + } + + if (pBTinfo->BtAsocEntry[EntryNum].BtCurrentState != HCI_STATE_CONNECTED) { + bthci_EventLogicalLinkComplete(padapter, + HCI_STATUS_CMD_DISALLOW, 0, 0, 0, EntryNum); + } else { + u8 i, find = 0; + + pBtMgnt->bLogLinkInProgress = true; + + /* find an unused logical link index and copy the data */ + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle == 0) { + enum hci_status LogCompEventstatus = HCI_STATUS_SUCCESS; + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtPhyLinkhandle = *((u8 *)pHciCmd->Data); + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle = AssignLogHandle; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("BuildLogicalLink, EntryNum = %d, physical link handle = 0x%x, logical link handle = 0x%x\n", + EntryNum, pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle)); + memcpy(&pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].Tx_Flow_Spec, + &TxFlowSpec, sizeof(struct hci_flow_spec)); + memcpy(&pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].Rx_Flow_Spec, + &RxFlowSpec, sizeof(struct hci_flow_spec)); + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCompleteEventIsSet = false; + + if (pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCancelCMDIsSetandComplete) + LogCompEventstatus = HCI_STATUS_UNKNOW_CONNECT_ID; + bthci_EventLogicalLinkComplete(padapter, + LogCompEventstatus, + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtPhyLinkhandle, + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle, i, EntryNum); + + pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCompleteEventIsSet = true; + + find = 1; + pBtMgnt->BtCurrentLogLinkhandle = AssignLogHandle; + AssignLogHandle++; + break; + } + } + + if (!find) { + bthci_EventLogicalLinkComplete(padapter, + HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE, 0, 0, 0, EntryNum); + } + pBtMgnt->bLogLinkInProgress = false; + } + } else { + bthci_EventLogicalLinkComplete(padapter, + HCI_STATUS_CONTROLLER_BUSY, 0, 0, 0, EntryNum); + } + +} + +static void +bthci_StartBeaconAndConnect( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd, + u8 CurrentAssocNum + ) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("StartBeaconAndConnect, CurrentAssocNum =%d, AMPRole =%d\n", + CurrentAssocNum, + pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole)); + + if (!pBtMgnt->CheckChnlIsSuit) { + bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND, CurrentAssocNum, INVALID_PL_HANDLE); + bthci_RemoveEntryByEntryNum(padapter, CurrentAssocNum); + return; + } + + if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_CREATOR) { + rsprintf((char *)pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 32, "AMP-%02x-%02x-%02x-%02x-%02x-%02x", + padapter->eeprompriv.mac_addr[0], + padapter->eeprompriv.mac_addr[1], + padapter->eeprompriv.mac_addr[2], + padapter->eeprompriv.mac_addr[3], + padapter->eeprompriv.mac_addr[4], + padapter->eeprompriv.mac_addr[5]); + } else if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_JOINER) { + rsprintf((char *)pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 32, "AMP-%02x-%02x-%02x-%02x-%02x-%02x", + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[0], + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[1], + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[2], + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[3], + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[4], + pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[5]); + } + + FillOctetString(pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsid, pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 21); + pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsid.Length = 21; + + /* To avoid set the start ap or connect twice, or the original connection will be disconnected. */ + if (!pBtMgnt->bBTConnectInProgress) { + pBtMgnt->bBTConnectInProgress = true; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress ON!!\n")); + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_STARTING, STATE_CMD_MAC_START_COMPLETE, CurrentAssocNum); + + /* 20100325 Joseph: Check RF ON/OFF. */ + /* If RF OFF, it reschedule connecting operation after 50ms. */ + if (!bthci_CheckRfStateBeforeConnect(padapter)) + return; + + if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_CREATOR) { + /* These macros need braces */ + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTING, STATE_CMD_MAC_CONNECT_COMPLETE, CurrentAssocNum); + } else if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_JOINER) { + bthci_ResponderStartToScan(padapter); + } + } + RT_PRINT_STR(_module_rtl871x_mlme_c_, _drv_notice_, + "StartBeaconAndConnect, SSID:\n", + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].BTSsid.Octet, + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].BTSsid.Length); +} + +static void bthci_ResetBtMgnt(struct bt_mgnt *pBtMgnt) +{ + pBtMgnt->BtOperationOn = false; + pBtMgnt->bBTConnectInProgress = false; + pBtMgnt->bLogLinkInProgress = false; + pBtMgnt->bPhyLinkInProgress = false; + pBtMgnt->bPhyLinkInProgressStartLL = false; + pBtMgnt->DisconnectEntryNum = 0xff; + pBtMgnt->bStartSendSupervisionPkt = false; + pBtMgnt->JoinerNeedSendAuth = false; + pBtMgnt->CurrentBTConnectionCnt = 0; + pBtMgnt->BTCurrentConnectType = BT_DISCONNECT; + pBtMgnt->BTReceiveConnectPkt = BT_DISCONNECT; + pBtMgnt->BTAuthCount = 0; + pBtMgnt->btLogoTest = 0; +} + +static void bthci_ResetBtHciInfo(struct bt_hci_info *pBtHciInfo) +{ + pBtHciInfo->BTEventMask = 0; + pBtHciInfo->BTEventMaskPage2 = 0; + pBtHciInfo->ConnAcceptTimeout = 10000; + pBtHciInfo->PageTimeout = 0x30; + pBtHciInfo->LocationDomainAware = 0x0; + pBtHciInfo->LocationDomain = 0x5858; + pBtHciInfo->LocationDomainOptions = 0x58; + pBtHciInfo->LocationOptions = 0x0; + pBtHciInfo->FlowControlMode = 0x1; /* 0:Packet based data flow control mode(BR/EDR), 1: Data block based data flow control mode(AMP). */ + + pBtHciInfo->enFlush_LLH = 0; + pBtHciInfo->FLTO_LLH = 0; + + /* Test command only */ + pBtHciInfo->bTestIsEnd = true; + pBtHciInfo->bInTestMode = false; + pBtHciInfo->bTestNeedReport = false; + pBtHciInfo->TestScenario = 0xff; + pBtHciInfo->TestReportInterval = 0x01; + pBtHciInfo->TestCtrType = 0x5d; + pBtHciInfo->TestEventType = 0x00; + pBtHciInfo->TestNumOfFrame = 0; + pBtHciInfo->TestNumOfErrFrame = 0; + pBtHciInfo->TestNumOfBits = 0; + pBtHciInfo->TestNumOfErrBits = 0; +} + +static void bthci_ResetBtSec(struct rtw_adapter *padapter, struct bt_security *pBtSec) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + + /* Set BT used HW or SW encrypt !! */ + if (GET_HAL_DATA(padapter)->bBTMode) + pBtSec->bUsedHwEncrypt = true; + else + pBtSec->bUsedHwEncrypt = false; + RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("%s: bUsedHwEncrypt =%d\n", __func__, pBtSec->bUsedHwEncrypt)); + + pBtSec->RSNIE.Octet = pBtSec->RSNIEBuf; +} + +static void bthci_ResetBtExtInfo(struct bt_mgnt *pBtMgnt) +{ + u8 i; + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = 0; + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = 0; + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = 0; + pBtMgnt->ExtConfig.linkInfo[i].BTProfile = BT_PROFILE_NONE; + pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = BT_SPEC_2_1_EDR; + pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI = 0; + pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = BT_PROFILE_NONE; + pBtMgnt->ExtConfig.linkInfo[i].linkRole = BT_LINK_MASTER; + } + + pBtMgnt->ExtConfig.CurrentConnectHandle = 0; + pBtMgnt->ExtConfig.CurrentIncomingTrafficMode = 0; + pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode = 0; + pBtMgnt->ExtConfig.MIN_BT_RSSI = 0; + pBtMgnt->ExtConfig.NumberOfHandle = 0; + pBtMgnt->ExtConfig.NumberOfSCO = 0; + pBtMgnt->ExtConfig.CurrentBTStatus = 0; + pBtMgnt->ExtConfig.HCIExtensionVer = 0; + + pBtMgnt->ExtConfig.bManualControl = false; + pBtMgnt->ExtConfig.bBTBusy = false; + pBtMgnt->ExtConfig.bBTA2DPBusy = false; +} + +static enum hci_status bthci_CmdReset(struct rtw_adapter *_padapter, u8 bNeedSendEvent) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct rtw_adapter *padapter; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_hci_info *pBtHciInfo; + struct bt_security *pBtSec; + struct bt_dgb *pBtDbg; + u8 i; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_CmdReset()\n")); + + padapter = GetDefaultAdapter(_padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtHciInfo = &pBTInfo->BtHciInfo; + pBtSec = &pBTInfo->BtSec; + pBtDbg = &pBTInfo->BtDbg; + + pBTInfo->padapter = padapter; + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) + bthci_ResetEntry(padapter, i); + + bthci_ResetBtMgnt(pBtMgnt); + bthci_ResetBtHciInfo(pBtHciInfo); + bthci_ResetBtSec(padapter, pBtSec); + + pBtMgnt->BTChannel = BT_Default_Chnl; + pBtMgnt->CheckChnlIsSuit = true; + + pBTInfo->BTBeaconTmrOn = false; + + pBtMgnt->bCreateSpportQos = true; + + del_timer_sync(&pBTInfo->BTHCIDiscardAclDataTimer); + del_timer_sync(&pBTInfo->BTBeaconTimer); + + HALBT_SetRtsCtsNoLenLimit(padapter); + /* */ + /* Maybe we need to take care Group != AES case !! */ + /* now we Pairwise and Group all used AES !! */ + + bthci_ResetBtExtInfo(pBtMgnt); + + /* send command complete event here when all data are received. */ + if (bNeedSendEvent) { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_RESET, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdWriteRemoteAMPAssoc( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 CurrentAssocNum; + u8 PhyLinkHandle; + + pBtDbg->dbgHciInfo.hciCmdCntWriteRemoteAmpAssoc++; + PhyLinkHandle = *((u8 *)pHciCmd->Data); + CurrentAssocNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle); + + if (CurrentAssocNum == 0xff) { + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, No such Handle in the Entry\n")); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle); + return status; + } + + if (pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment == NULL) { + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, AMP controller is busy\n")); + status = HCI_STATUS_CONTROLLER_BUSY; + bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle); + return status; + } + + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.BtPhyLinkhandle = PhyLinkHandle;/* u8 *)pHciCmd->Data); */ + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar = *((u16 *)((u8 *)pHciCmd->Data+1)); + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen = *((u16 *)((u8 *)pHciCmd->Data+3)); + + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, LenSoFar = 0x%x, AssocRemLen = 0x%x\n", + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar, + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen)); + + RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), + ("WriteRemoteAMPAssoc fragment \n"), + pHciCmd->Data, + pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen+5); + if ((pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen) > MAX_AMP_ASSOC_FRAG_LEN) { + memcpy(((u8 *)pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment+(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar*(sizeof(u8)))), + (u8 *)pHciCmd->Data+5, + MAX_AMP_ASSOC_FRAG_LEN); + } else { + memcpy((u8 *)(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment)+(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar*(sizeof(u8))), + ((u8 *)pHciCmd->Data+5), + (pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen)); + + RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), "WriteRemoteAMPAssoc :\n", + pHciCmd->Data+5, pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen); + + if (!bthci_GetAssocInfo(padapter, CurrentAssocNum)) + status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; + + bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle); + + bthci_StartBeaconAndConnect(padapter, pHciCmd, CurrentAssocNum); + } + + return status; +} + +/* 7.3.13 */ +static enum hci_status bthci_CmdReadConnectionAcceptTimeout(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_CONNECTION_ACCEPT_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pu2Temp = (u16 *)&pRetPar[1]; /* Conn_Accept_Timeout */ + *pu2Temp = pBtHciInfo->ConnAcceptTimeout; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +/* 7.3.3 */ +static enum hci_status +bthci_CmdSetEventFilter( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + return status; +} + +/* 7.3.14 */ +static enum hci_status +bthci_CmdWriteConnectionAcceptTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u16 *pu2Temp; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pu2Temp = (u16 *)&pHciCmd->Data[0]; + pBtHciInfo->ConnAcceptTimeout = *pu2Temp; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("ConnAcceptTimeout = 0x%x", + pBtHciInfo->ConnAcceptTimeout)); + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdReadPageTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_PAGE_TIMEOUT, + status); + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Read PageTimeout = 0x%x\n", pBtHciInfo->PageTimeout)); + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pu2Temp = (u16 *)&pRetPar[1]; /* Page_Timeout */ + *pu2Temp = pBtHciInfo->PageTimeout; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdWritePageTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u16 *pu2Temp; + + pu2Temp = (u16 *)&pHciCmd->Data[0]; + pBtHciInfo->PageTimeout = *pu2Temp; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Write PageTimeout = 0x%x\n", + pBtHciInfo->PageTimeout)); + + /* send command complete event here when all data are received. */ + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_PAGE_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdReadLinkSupervisionTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + u8 physicalLinkHandle, EntryNum; + + physicalLinkHandle = *((u8 *)pHciCmd->Data); + + EntryNum = bthci_GetCurrentEntryNum(padapter, physicalLinkHandle); + + if (EntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLinkSupervisionTimeout, No such Handle in the Entry\n")); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + return status; + } + + if (pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle != physicalLinkHandle) + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + { + u8 localBuf[10] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_LINK_SUPERVISION_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + pRetPar[1] = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + pRetPar[2] = 0; + pu2Temp = (u16 *)&pRetPar[3]; /* Conn_Accept_Timeout */ + *pu2Temp = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout; + len += 5; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdWriteLinkSupervisionTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + u8 physicalLinkHandle, EntryNum; + + physicalLinkHandle = *((u8 *)pHciCmd->Data); + + EntryNum = bthci_GetCurrentEntryNum(padapter, physicalLinkHandle); + + if (EntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("WriteLinkSupervisionTimeout, No such Handle in the Entry\n")); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } else { + if (pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle != physicalLinkHandle) { + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } else { + pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout = *((u16 *)(((u8 *)pHciCmd->Data)+2)); + RTPRINT(FIOCTL, IOCTL_STATE, ("BT Write LinkSuperversionTimeout[%d] = 0x%x\n", + EntryNum, pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout)); + } + } + + { + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_LINK_SUPERVISION_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + pRetPar[1] = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; + pRetPar[2] = 0; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdEnhancedFlush( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTinfo->BtHciInfo; + u16 logicHandle; + u8 Packet_Type; + + logicHandle = *((u16 *)&pHciCmd->Data[0]); + Packet_Type = pHciCmd->Data[2]; + + if (Packet_Type != 0) + status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; + else + pBtHciInfo->enFlush_LLH = logicHandle; + + if (bthci_DiscardTxPackets(padapter, pBtHciInfo->enFlush_LLH)) + bthci_EventFlushOccurred(padapter, pBtHciInfo->enFlush_LLH); + + /* should send command status event */ + bthci_EventCommandStatus(padapter, + OGF_SET_EVENT_MASK_COMMAND, + HCI_ENHANCED_FLUSH, + status); + + if (pBtHciInfo->enFlush_LLH) { + bthci_EventEnhancedFlushComplete(padapter, pBtHciInfo->enFlush_LLH); + pBtHciInfo->enFlush_LLH = 0; + } + + return status; +} + +static enum hci_status +bthci_CmdReadLogicalLinkAcceptTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + + pu2Temp = (u16 *)&pRetPar[1]; /* Conn_Accept_Timeout */ + *pu2Temp = pBtHciInfo->LogicalAcceptTimeout; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdWriteLogicalLinkAcceptTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pBtHciInfo->LogicalAcceptTimeout = *((u16 *)pHciCmd->Data); + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status +bthci_CmdSetEventMask( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 *pu8Temp; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pu8Temp = (u8 *)&pHciCmd->Data[0]; + pBtHciInfo->BTEventMask = *pu8Temp; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("BTEventMask = 0x%"i64fmt"x\n", + pBtHciInfo->BTEventMask)); + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_SET_EVENT_MASK, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +/* 7.3.69 */ +static enum hci_status +bthci_CmdSetEventMaskPage2( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 *pu8Temp; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pu8Temp = (u8 *)&pHciCmd->Data[0]; + pBtHciInfo->BTEventMaskPage2 = *pu8Temp; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("BTEventMaskPage2 = 0x%"i64fmt"x\n", + pBtHciInfo->BTEventMaskPage2)); + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_SET_EVENT_MASK_PAGE_2, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdReadLocationData( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[12] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_LOCATION_DATA, + status); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainAware = 0x%x\n", pBtHciInfo->LocationDomainAware)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Domain = 0x%x\n", pBtHciInfo->LocationDomain)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainOptions = 0x%x\n", pBtHciInfo->LocationDomainOptions)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Options = 0x%x\n", pBtHciInfo->LocationOptions)); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + + pRetPar[1] = pBtHciInfo->LocationDomainAware; /* 0x0; Location_Domain_Aware */ + pu2Temp = (u16 *)&pRetPar[2]; /* Location_Domain */ + *pu2Temp = pBtHciInfo->LocationDomain; /* 0x5858; */ + pRetPar[4] = pBtHciInfo->LocationDomainOptions; /* 0x58; Location_Domain_Options */ + pRetPar[5] = pBtHciInfo->LocationOptions; /* 0x0; Location_Options */ + len += 6; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status +bthci_CmdWriteLocationData( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u16 *pu2Temp; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pBtHciInfo->LocationDomainAware = pHciCmd->Data[0]; + pu2Temp = (u16 *)&pHciCmd->Data[1]; + pBtHciInfo->LocationDomain = *pu2Temp; + pBtHciInfo->LocationDomainOptions = pHciCmd->Data[3]; + pBtHciInfo->LocationOptions = pHciCmd->Data[4]; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainAware = 0x%x\n", pBtHciInfo->LocationDomainAware)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Domain = 0x%x\n", pBtHciInfo->LocationDomain)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainOptions = 0x%x\n", pBtHciInfo->LocationDomainOptions)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Options = 0x%x\n", pBtHciInfo->LocationOptions)); + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_LOCATION_DATA, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdReadFlowControlMode( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[7] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_FLOW_CONTROL_MODE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + pRetPar[1] = pBtHciInfo->FlowControlMode; /* Flow Control Mode */ + len += 2; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status +bthci_CmdWriteFlowControlMode( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + pBtHciInfo->FlowControlMode = pHciCmd->Data[0]; + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_FLOW_CONTROL_MODE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdReadBestEffortFlushTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + u16 i, j, logicHandle; + u32 BestEffortFlushTimeout = 0xffffffff; + u8 find = 0; + + logicHandle = *((u16 *)pHciCmd->Data); + /* find an matched logical link index and copy the data */ + for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) { + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) { + BestEffortFlushTimeout = pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BestEffortFlushTimeout; + find = 1; + break; + } + } + } + + if (!find) + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + { + u8 localBuf[10] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u32 *pu4Temp; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + pu4Temp = (u32 *)&pRetPar[1]; /* Best_Effort_Flush_Timeout */ + *pu4Temp = BestEffortFlushTimeout; + len += 5; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + return status; +} + +static enum hci_status +bthci_CmdWriteBestEffortFlushTimeout( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + u16 i, j, logicHandle; + u32 BestEffortFlushTimeout = 0xffffffff; + u8 find = 0; + + logicHandle = *((u16 *)pHciCmd->Data); + BestEffortFlushTimeout = *((u32 *)(pHciCmd->Data+1)); + + /* find an matched logical link index and copy the data */ + for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) { + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) { + pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BestEffortFlushTimeout = BestEffortFlushTimeout; + find = 1; + break; + } + } + } + + if (!find) + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + return status; +} + +static enum hci_status +bthci_CmdShortRangeMode( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + u8 PhyLinkHandle, EntryNum, ShortRangeMode; + + PhyLinkHandle = pHciCmd->Data[0]; + ShortRangeMode = pHciCmd->Data[1]; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PLH = 0x%x, Short_Range_Mode = 0x%x\n", PhyLinkHandle, ShortRangeMode)); + + EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle); + if (EntryNum != 0xff) { + pBTInfo->BtAsocEntry[EntryNum].ShortRangeMode = ShortRangeMode; + } else { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("No such PLH(0x%x)\n", PhyLinkHandle)); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } + + bthci_EventCommandStatus(padapter, + OGF_SET_EVENT_MASK_COMMAND, + HCI_SHORT_RANGE_MODE, + status); + + bthci_EventShortRangeModeChangeComplete(padapter, status, ShortRangeMode, EntryNum); + + return status; +} + +static enum hci_status bthci_CmdReadLocalSupportedCommands(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar, *pSupportedCmds; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + /* send command complete event here when all data are received. */ + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_INFORMATIONAL_PARAMETERS, + HCI_READ_LOCAL_SUPPORTED_COMMANDS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + pSupportedCmds = &pRetPar[1]; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[5]= 0xc0\nBit [6]= Set Event Mask, [7]= Reset\n")); + pSupportedCmds[5] = 0xc0; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[6]= 0x01\nBit [0]= Set Event Filter\n")); + pSupportedCmds[6] = 0x01; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[7]= 0x0c\nBit [2]= Read Connection Accept Timeout, [3]= Write Connection Accept Timeout\n")); + pSupportedCmds[7] = 0x0c; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[10]= 0x80\nBit [7]= Host Number Of Completed Packets\n")); + pSupportedCmds[10] = 0x80; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[11]= 0x03\nBit [0]= Read Link Supervision Timeout, [1]= Write Link Supervision Timeout\n")); + pSupportedCmds[11] = 0x03; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[14]= 0xa8\nBit [3]= Read Local Version Information, [5]= Read Local Supported Features, [7]= Read Buffer Size\n")); + pSupportedCmds[14] = 0xa8; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[15]= 0x1c\nBit [2]= Read Failed Contact Count, [3]= Reset Failed Contact Count, [4]= Get Link Quality\n")); + pSupportedCmds[15] = 0x1c; + /* pSupportedCmds[16] = 0x04; */ + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[19]= 0x40\nBit [6]= Enhanced Flush\n")); + pSupportedCmds[19] = 0x40; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[21]= 0xff\nBit [0]= Create Physical Link, [1]= Accept Physical Link, [2]= Disconnect Physical Link, [3]= Create Logical Link\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), (" [4]= Accept Logical Link, [5]= Disconnect Logical Link, [6]= Logical Link Cancel, [7]= Flow Spec Modify\n")); + pSupportedCmds[21] = 0xff; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[22]= 0xff\nBit [0]= Read Logical Link Accept Timeout, [1]= Write Logical Link Accept Timeout, [2]= Set Event Mask Page 2, [3]= Read Location Data\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), (" [4]= Write Location Data, [5]= Read Local AMP Info, [6]= Read Local AMP_ASSOC, [7]= Write Remote AMP_ASSOC\n")); + pSupportedCmds[22] = 0xff; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[23]= 0x07\nBit [0]= Read Flow Control Mode, [1]= Write Flow Control Mode, [2]= Read Data Block Size\n")); + pSupportedCmds[23] = 0x07; + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[24]= 0x1c\nBit [2]= Read Best Effort Flush Timeout, [3]= Write Best Effort Flush Timeout, [4]= Short Range Mode\n")); + pSupportedCmds[24] = 0x1c; + len += 64; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status bthci_CmdReadLocalSupportedFeatures(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + /* send command complete event here when all data are received. */ + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_INFORMATIONAL_PARAMETERS, + HCI_READ_LOCAL_SUPPORTED_FEATURES, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 9; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status bthci_CmdReadLocalAMPAssoc(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 PhyLinkHandle, EntryNum; + + pBtDbg->dbgHciInfo.hciCmdCntReadLocalAmpAssoc++; + PhyLinkHandle = *((u8 *)pHciCmd->Data); + EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle); + + if ((EntryNum == 0xff) && PhyLinkHandle != 0) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, EntryNum = %d !!!!!, physical link handle = 0x%x\n", + EntryNum, PhyLinkHandle)); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } else if (pBtMgnt->bPhyLinkInProgressStartLL) { + status = HCI_STATUS_UNKNOW_CONNECT_ID; + pBtMgnt->bPhyLinkInProgressStartLL = false; + } else { + pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.BtPhyLinkhandle = *((u8 *)pHciCmd->Data); + pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar = *((u16 *)((u8 *)pHciCmd->Data+1)); + pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.MaxRemoteASSOCLen = *((u16 *)((u8 *)pHciCmd->Data+3)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("ReadLocalAMPAssoc, LenSoFar =%d, MaxRemoteASSOCLen =%d\n", + pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar, + pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.MaxRemoteASSOCLen)); + } + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, EntryNum = %d !!!!!, physical link handle = 0x%x, LengthSoFar = %x \n", + EntryNum, PhyLinkHandle, pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar)); + + /* send command complete event here when all data are received. */ + { + struct packet_irp_hcievent_data *PPacketIrpEvent; + + /* PVOID buffer = padapter->IrpHCILocalbuf.Ptr; */ + u8 localBuf[TmpLocalBufSize] = ""; + u16 *pRemainLen; + u32 totalLen = 0; + u16 typeLen = 0, remainLen = 0, ret_index = 0; + u8 *pRetPar; + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + totalLen += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_READ_LOCAL_AMP_ASSOC, + status); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, Remaining_Len =%d \n", remainLen)); + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[totalLen]; + pRetPar[0] = status; /* status */ + pRetPar[1] = *((u8 *)pHciCmd->Data); + pRemainLen = (u16 *)&pRetPar[2]; /* AMP_ASSOC_Remaining_Length */ + totalLen += 4; /* 0]~[3] */ + ret_index = 4; + + typeLen = bthci_AssocMACAddr(padapter, &pRetPar[ret_index]); + totalLen += typeLen; + remainLen += typeLen; + ret_index += typeLen; + typeLen = bthci_AssocPreferredChannelList(padapter, &pRetPar[ret_index], EntryNum); + totalLen += typeLen; + remainLen += typeLen; + ret_index += typeLen; + typeLen = bthci_PALCapabilities(padapter, &pRetPar[ret_index]); + totalLen += typeLen; + remainLen += typeLen; + ret_index += typeLen; + typeLen = bthci_AssocPALVer(padapter, &pRetPar[ret_index]); + totalLen += typeLen; + remainLen += typeLen; + PPacketIrpEvent->Length = (u8)totalLen; + *pRemainLen = remainLen; /* AMP_ASSOC_Remaining_Length */ + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, Remaining_Len =%d \n", remainLen)); + RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("AMP_ASSOC_fragment : \n"), PPacketIrpEvent->Data, totalLen); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, totalLen+2); + } + + return status; +} + +static enum hci_status bthci_CmdReadFailedContactCounter(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 handle; + + handle = *((u16 *)pHciCmd->Data); + /* send command complete event here when all data are received. */ + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_READ_FAILED_CONTACT_COUNTER, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = TWOBYTE_LOWBYTE(handle); + pRetPar[2] = TWOBYTE_HIGHTBYTE(handle); + pRetPar[3] = TWOBYTE_LOWBYTE(pBtHciInfo->FailContactCount); + pRetPar[4] = TWOBYTE_HIGHTBYTE(pBtHciInfo->FailContactCount); + len += 5; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdResetFailedContactCounter( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u16 handle; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + handle = *((u16 *)pHciCmd->Data); + pBtHciInfo->FailContactCount = 0; + + /* send command complete event here when all data are received. */ + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_RESET_FAILED_CONTACT_COUNTER, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = TWOBYTE_LOWBYTE(handle); + pRetPar[2] = TWOBYTE_HIGHTBYTE(handle); + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +/* */ +/* BT 3.0+HS [Vol 2] 7.4.1 */ +/* */ +static enum hci_status +bthci_CmdReadLocalVersionInformation( + struct rtw_adapter *padapter + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + /* send command complete event here when all data are received. */ + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_INFORMATIONAL_PARAMETERS, + HCI_READ_LOCAL_VERSION_INFORMATION, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = 0x05; /* HCI_Version */ + pu2Temp = (u16 *)&pRetPar[2]; /* HCI_Revision */ + *pu2Temp = 0x0001; + pRetPar[4] = 0x05; /* LMP/PAL_Version */ + pu2Temp = (u16 *)&pRetPar[5]; /* Manufacturer_Name */ + *pu2Temp = 0x005d; + pu2Temp = (u16 *)&pRetPar[7]; /* LMP/PAL_Subversion */ + *pu2Temp = 0x0001; + len += 9; + PPacketIrpEvent->Length = len; + + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LOCAL_VERSION_INFORMATION\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("Status %x\n", status)); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI_Version = 0x05\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI_Revision = 0x0001\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LMP/PAL_Version = 0x05\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("Manufacturer_Name = 0x0001\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LMP/PAL_Subversion = 0x0001\n")); + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +/* 7.4.7 */ +static enum hci_status bthci_CmdReadDataBlockSize(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_INFORMATIONAL_PARAMETERS, + HCI_READ_DATA_BLOCK_SIZE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = HCI_STATUS_SUCCESS; /* status */ + pu2Temp = (u16 *)&pRetPar[1]; /* Max_ACL_Data_Packet_Length */ + *pu2Temp = Max80211PALPDUSize; + + pu2Temp = (u16 *)&pRetPar[3]; /* Data_Block_Length */ + *pu2Temp = Max80211PALPDUSize; + pu2Temp = (u16 *)&pRetPar[5]; /* Total_Num_Data_Blocks */ + *pu2Temp = BTTotalDataBlockNum; + len += 7; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +/* 7.4.5 */ +static enum hci_status bthci_CmdReadBufferSize(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_INFORMATIONAL_PARAMETERS, + HCI_READ_BUFFER_SIZE, + status); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Synchronous_Data_Packet_Length = 0x%x\n", BTSynDataPacketLength)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Total_Num_ACL_Data_Packets = 0x%x\n", BTTotalDataBlockNum)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Total_Num_Synchronous_Data_Packets = 0x%x\n", BTTotalDataBlockNum)); + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pu2Temp = (u16 *)&pRetPar[1]; /* HC_ACL_Data_Packet_Length */ + *pu2Temp = Max80211PALPDUSize; + + pRetPar[3] = BTSynDataPacketLength; /* HC_Synchronous_Data_Packet_Length */ + pu2Temp = (u16 *)&pRetPar[4]; /* HC_Total_Num_ACL_Data_Packets */ + *pu2Temp = BTTotalDataBlockNum; + pu2Temp = (u16 *)&pRetPar[6]; /* HC_Total_Num_Synchronous_Data_Packets */ + *pu2Temp = BTTotalDataBlockNum; + len += 8; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status bthci_CmdReadLocalAMPInfo(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct pwrctrl_priv *ppwrctrl = &padapter->pwrctrlpriv; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + u32 *pu4Temp; + u32 TotalBandwidth = BTTOTALBANDWIDTH, MaxBandGUBandwidth = BTMAXBANDGUBANDWIDTH; + u8 ControlType = 0x01, AmpStatus = 0x01; + u32 MaxFlushTimeout = 10000, BestEffortFlushTimeout = 5000; + u16 MaxPDUSize = Max80211PALPDUSize, PalCap = 0x1, AmpAssocLen = Max80211AMPASSOCLen, MinLatency = 20; + + if ((ppwrctrl->rfoff_reason & RF_CHANGE_BY_HW) || + (ppwrctrl->rfoff_reason & RF_CHANGE_BY_SW)) { + AmpStatus = AMP_STATUS_NO_CAPACITY_FOR_BT; + } + + PlatformZeroMemory(&localBuf[0], TmpLocalBufSize); + /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_READ_LOCAL_AMP_INFO, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = AmpStatus; /* AMP_Status */ + pu4Temp = (u32 *)&pRetPar[2]; /* Total_Bandwidth */ + *pu4Temp = TotalBandwidth; /* 0x19bfcc00;0x7530; */ + pu4Temp = (u32 *)&pRetPar[6]; /* Max_Guaranteed_Bandwidth */ + *pu4Temp = MaxBandGUBandwidth; /* 0x19bfcc00;0x4e20; */ + pu4Temp = (u32 *)&pRetPar[10]; /* Min_Latency */ + *pu4Temp = MinLatency; /* 150; */ + pu4Temp = (u32 *)&pRetPar[14]; /* Max_PDU_Size */ + *pu4Temp = MaxPDUSize; + pRetPar[18] = ControlType; /* Controller_Type */ + pu2Temp = (u16 *)&pRetPar[19]; /* PAL_Capabilities */ + *pu2Temp = PalCap; + pu2Temp = (u16 *)&pRetPar[21]; /* AMP_ASSOC_Length */ + *pu2Temp = AmpAssocLen; + pu4Temp = (u32 *)&pRetPar[23]; /* Max_Flush_Timeout */ + *pu4Temp = MaxFlushTimeout; + pu4Temp = (u32 *)&pRetPar[27]; /* Best_Effort_Flush_Timeout */ + *pu4Temp = BestEffortFlushTimeout; + len += 31; + PPacketIrpEvent->Length = len; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("AmpStatus = 0x%x\n", + AmpStatus)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("TotalBandwidth = 0x%x, MaxBandGUBandwidth = 0x%x, MinLatency = 0x%x, \n MaxPDUSize = 0x%x, ControlType = 0x%x\n", + TotalBandwidth, MaxBandGUBandwidth, MinLatency, MaxPDUSize, ControlType)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PalCap = 0x%x, AmpAssocLen = 0x%x, MaxFlushTimeout = 0x%x, BestEffortFlushTimeout = 0x%x\n", + PalCap, AmpAssocLen, MaxFlushTimeout, BestEffortFlushTimeout)); + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status +bthci_CmdCreatePhysicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntCreatePhyLink++; + + status = bthci_BuildPhysicalLink(padapter, + pHciCmd, HCI_CREATE_PHYSICAL_LINK); + + return status; +} + +static enum hci_status +bthci_CmdReadLinkQuality( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + u16 PLH; + u8 EntryNum, LinkQuality = 0x55; + + PLH = *((u16 *)&pHciCmd->Data[0]); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PLH = 0x%x\n", PLH)); + + EntryNum = bthci_GetCurrentEntryNum(padapter, (u8)PLH); + if (EntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("No such PLH(0x%x)\n", PLH)); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } + + { + u8 localBuf[11] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_STATUS_PARAMETERS, + HCI_READ_LINK_QUALITY, + status); + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, (" PLH = 0x%x\n Link Quality = 0x%x\n", PLH, LinkQuality)); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + *((u16 *)&pRetPar[1]) = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle; /* Handle */ + pRetPar[3] = 0x55; /* Link Quailty */ + len += 4; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status bthci_CmdReadRSSI(struct rtw_adapter *padapter) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + return status; +} + +static enum hci_status +bthci_CmdCreateLogicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntCreateLogLink++; + + bthci_BuildLogicalLink(padapter, pHciCmd, + HCI_CREATE_LOGICAL_LINK); + + return status; +} + +static enum hci_status +bthci_CmdAcceptLogicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntAcceptLogLink++; + + bthci_BuildLogicalLink(padapter, pHciCmd, + HCI_ACCEPT_LOGICAL_LINK); + + return status; +} + +static enum hci_status +bthci_CmdDisconnectLogicalLink( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTinfo->BtDbg; + u16 logicHandle; + u8 i, j, find = 0, LogLinkCount = 0; + + pBtDbg->dbgHciInfo.hciCmdCntDisconnectLogLink++; + + logicHandle = *((u16 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DisconnectLogicalLink, logicHandle = 0x%x\n", logicHandle)); + + /* find an created logical link index and clear the data */ + for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) { + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DisconnectLogicalLink, logicHandle is matched 0x%x\n", logicHandle)); + bthci_ResetFlowSpec(padapter, j, i); + find = 1; + pBtMgnt->DisconnectEntryNum = j; + break; + } + } + } + + if (!find) + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + /* To check each */ + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[pBtMgnt->DisconnectEntryNum].LogLinkCmdData[i].BtLogLinkhandle != 0) + LogLinkCount++; + } + + /* When we receive Create logical link command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + HCI_DISCONNECT_LOGICAL_LINK, + status); + /* */ + /* When we determines the logical link is established, we should send command complete event. */ + /* */ + if (status == HCI_STATUS_SUCCESS) { + bthci_EventDisconnectLogicalLinkComplete(padapter, status, + logicHandle, HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST); + } + + if (LogLinkCount == 0) + mod_timer(&pBTinfo->BTDisconnectPhyLinkTimer, + jiffies + msecs_to_jiffies(100)); + + return status; +} + +static enum hci_status +bthci_CmdLogicalLinkCancel(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt; + u8 CurrentEntryNum, CurrentLogEntryNum; + + u8 physicalLinkHandle, TxFlowSpecID, i; + u16 CurrentLogicalHandle; + + physicalLinkHandle = *((u8 *)pHciCmd->Data); + TxFlowSpecID = *(((u8 *)pHciCmd->Data)+1); + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, physicalLinkHandle = 0x%x, TxFlowSpecID = 0x%x\n", + physicalLinkHandle, TxFlowSpecID)); + + CurrentEntryNum = pBtMgnt->CurrentConnectEntryNum; + CurrentLogicalHandle = pBtMgnt->BtCurrentLogLinkhandle; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("CurrentEntryNum = 0x%x, CurrentLogicalHandle = 0x%x\n", + CurrentEntryNum, CurrentLogicalHandle)); + + CurrentLogEntryNum = 0xff; + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if ((CurrentLogicalHandle == pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[i].BtLogLinkhandle) && + (physicalLinkHandle == pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[i].BtPhyLinkhandle)) { + CurrentLogEntryNum = i; + break; + } + } + + if (CurrentLogEntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, CurrentLogEntryNum == 0xff !!!!\n")); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + return status; + } else { + if (pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].bLLCompleteEventIsSet) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, LLCompleteEventIsSet!!!!\n")); + status = HCI_STATUS_ACL_CONNECT_EXISTS; + } + } + + { + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + LINK_CONTROL_COMMANDS, + HCI_LOGICAL_LINK_CANCEL, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].BtPhyLinkhandle; + pRetPar[2] = pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].BtTxFlowSpecID; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].bLLCancelCMDIsSetandComplete = true; + + return status; +} + +static enum hci_status +bthci_CmdFlowSpecModify(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTinfo = GET_BT_INFO(padapter); + u8 i, j, find = 0; + u16 logicHandle; + + logicHandle = *((u16 *)pHciCmd->Data); + /* find an matched logical link index and copy the data */ + for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) { + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) { + memcpy(&pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Tx_Flow_Spec, + &pHciCmd->Data[2], sizeof(struct hci_flow_spec)); + memcpy(&pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Rx_Flow_Spec, + &pHciCmd->Data[18], sizeof(struct hci_flow_spec)); + + bthci_CheckLogLinkBehavior(padapter, pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Tx_Flow_Spec); + find = 1; + break; + } + } + } + RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("FlowSpecModify, LLH = 0x%x, \n", logicHandle)); + + /* When we receive Flow Spec Modify command, we should send command status event first. */ + bthci_EventCommandStatus(padapter, + LINK_CONTROL_COMMANDS, + HCI_FLOW_SPEC_MODIFY, + HCI_STATUS_SUCCESS); + + if (!find) + status = HCI_STATUS_UNKNOW_CONNECT_ID; + + bthci_EventSendFlowSpecModifyComplete(padapter, status, logicHandle); + + return status; +} + +static enum hci_status +bthci_CmdAcceptPhysicalLink(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntAcceptPhyLink++; + + status = bthci_BuildPhysicalLink(padapter, + pHciCmd, HCI_ACCEPT_PHYSICAL_LINK); + + return status; +} + +static enum hci_status +bthci_CmdDisconnectPhysicalLink(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 PLH, CurrentEntryNum, PhysLinkDisconnectReason; + + pBtDbg->dbgHciInfo.hciCmdCntDisconnectPhyLink++; + + PLH = *((u8 *)pHciCmd->Data); + PhysLinkDisconnectReason = (*((u8 *)pHciCmd->Data+1)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_PHYSICAL_LINK PhyHandle = 0x%x, Reason = 0x%x\n", + PLH, PhysLinkDisconnectReason)); + + CurrentEntryNum = bthci_GetCurrentEntryNum(padapter, PLH); + + if (CurrentEntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, + ("DisconnectPhysicalLink, No such Handle in the Entry\n")); + status = HCI_STATUS_UNKNOW_CONNECT_ID; + } else { + pBTInfo->BtAsocEntry[CurrentEntryNum].PhyLinkDisconnectReason = + (enum hci_status)PhysLinkDisconnectReason; + } + /* Send HCI Command status event to AMP. */ + bthci_EventCommandStatus(padapter, LINK_CONTROL_COMMANDS, + HCI_DISCONNECT_PHYSICAL_LINK, status); + + if (status != HCI_STATUS_SUCCESS) + return status; + + /* The macros below require { and } in the if statement */ + if (pBTInfo->BtAsocEntry[CurrentEntryNum].BtCurrentState == HCI_STATE_DISCONNECTED) { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_DISCONNECT_PHY_LINK, CurrentEntryNum); + } else { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_DISCONNECT_PHY_LINK, CurrentEntryNum); + } + return status; +} + +static enum hci_status +bthci_CmdSetACLLinkDataFlowMode(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp; + + pBtMgnt->ExtConfig.CurrentConnectHandle = *((u16 *)pHciCmd->Data); + pBtMgnt->ExtConfig.CurrentIncomingTrafficMode = *((u8 *)pHciCmd->Data)+2; + pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode = *((u8 *)pHciCmd->Data)+3; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Connection Handle = 0x%x, Incoming Traffic mode = 0x%x, Outgoing Traffic mode = 0x%x", + pBtMgnt->ExtConfig.CurrentConnectHandle, + pBtMgnt->ExtConfig.CurrentIncomingTrafficMode, + pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode)); + + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_SET_ACL_LINK_DATA_FLOW_MODE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + pu2Temp = (u16 *)&pRetPar[1]; + *pu2Temp = pBtMgnt->ExtConfig.CurrentConnectHandle; + len += 3; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + return status; +} + +static enum hci_status +bthci_CmdSetACLLinkStatus(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 i; + u8 *pTriple; + + pBtDbg->dbgHciInfo.hciCmdCntSetAclLinkStatus++; + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "SetACLLinkStatus, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + + /* Only Core Stack v251 and later version support this command. */ + pBtMgnt->bSupportProfile = true; + + pBtMgnt->ExtConfig.NumberOfHandle = *((u8 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfHandle = 0x%x\n", pBtMgnt->ExtConfig.NumberOfHandle)); + + pTriple = &pHciCmd->Data[1]; + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]); + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = pTriple[2]; + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = pTriple[3]; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, + ("Connection_Handle = 0x%x, Incoming Traffic mode = 0x%x, Outgoing Traffic Mode = 0x%x\n", + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle, + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode, + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode)); + pTriple += 4; + } + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_SET_ACL_LINK_STATUS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdSetSCOLinkStatus( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntSetScoLinkStatus++; + pBtMgnt->ExtConfig.NumberOfSCO = *((u8 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfSCO = 0x%x\n", + pBtMgnt->ExtConfig.NumberOfSCO)); + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_SET_SCO_LINK_STATUS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdSetRSSIValue( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + s8 min_bt_rssi = 0; + u8 i; + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + if (pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle == *((u16 *)&pHciCmd->Data[0])) { + pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI = (s8)(pHciCmd->Data[2]); + RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL, + ("Connection_Handle = 0x%x, RSSI = %d \n", + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle, + pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI)); + } + /* get the minimum bt rssi value */ + if (pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI <= min_bt_rssi) + min_bt_rssi = pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI; + } + + pBtMgnt->ExtConfig.MIN_BT_RSSI = min_bt_rssi; + RTPRINT(FBT, BT_TRACE, ("[bt rssi], the min rssi is %d\n", min_bt_rssi)); + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_SET_RSSI_VALUE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdSetCurrentBluetoothStatus( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + pBtMgnt->ExtConfig.CurrentBTStatus = *((u8 *)&pHciCmd->Data[0]); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("SetCurrentBluetoothStatus, CurrentBTStatus = 0x%x\n", + pBtMgnt->ExtConfig.CurrentBTStatus)); + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_SET_CURRENT_BLUETOOTH_STATUS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdExtensionVersionNotify( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntExtensionVersionNotify++; + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "ExtensionVersionNotify, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + + pBtMgnt->ExtConfig.HCIExtensionVer = *((u16 *)&pHciCmd->Data[0]); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = 0x%x\n", pBtMgnt->ExtConfig.HCIExtensionVer)); + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_EXTENSION_VERSION_NOTIFY, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdLinkStatusNotify( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 i; + u8 *pTriple; + + pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++; + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + + /* Current only RTL8723 support this command. */ + pBtMgnt->bSupportProfile = true; + + pBtMgnt->ExtConfig.NumberOfHandle = *((u8 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfHandle = 0x%x\n", pBtMgnt->ExtConfig.NumberOfHandle)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer)); + + pTriple = &pHciCmd->Data[1]; + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) { + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]); + pBtMgnt->ExtConfig.linkInfo[i].BTProfile = pTriple[2]; + pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = pTriple[3]; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, + ("Connection_Handle = 0x%x, BTProfile =%d, BTSpec =%d\n", + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle, + pBtMgnt->ExtConfig.linkInfo[i].BTProfile, + pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec)); + pTriple += 4; + } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]); + pBtMgnt->ExtConfig.linkInfo[i].BTProfile = pTriple[2]; + pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = pTriple[3]; + pBtMgnt->ExtConfig.linkInfo[i].linkRole = pTriple[4]; + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, + ("Connection_Handle = 0x%x, BTProfile =%d, BTSpec =%d, LinkRole =%d\n", + pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle, + pBtMgnt->ExtConfig.linkInfo[i].BTProfile, + pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec, + pBtMgnt->ExtConfig.linkInfo[i].linkRole)); + pTriple += 5; + } + + } + BTHCI_UpdateBTProfileRTKToMoto(padapter); + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_LINK_STATUS_NOTIFY, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdBtOperationNotify( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "Bt Operation notify, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + + pBtMgnt->ExtConfig.btOperationCode = *((u8 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("btOperationCode = 0x%x\n", pBtMgnt->ExtConfig.btOperationCode)); + switch (pBtMgnt->ExtConfig.btOperationCode) { + case HCI_BT_OP_NONE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Operation None!!\n")); + break; + case HCI_BT_OP_INQUIRY_START: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Inquire start!!\n")); + break; + case HCI_BT_OP_INQUIRY_FINISH: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Inquire finished!!\n")); + break; + case HCI_BT_OP_PAGING_START: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging is started!!\n")); + break; + case HCI_BT_OP_PAGING_SUCCESS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging complete successfully!!\n")); + break; + case HCI_BT_OP_PAGING_UNSUCCESS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging complete unsuccessfully!!\n")); + break; + case HCI_BT_OP_PAIRING_START: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Pairing start!!\n")); + break; + case HCI_BT_OP_PAIRING_FINISH: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Pairing finished!!\n")); + break; + case HCI_BT_OP_BT_DEV_ENABLE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : BT Device is enabled!!\n")); + break; + case HCI_BT_OP_BT_DEV_DISABLE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : BT Device is disabled!!\n")); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Unknown, error!!\n")); + break; + } + BTDM_AdjustForBtOperation(padapter); + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_BT_OPERATION_NOTIFY, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdEnableWifiScanNotify(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "Enable Wifi scan notify, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + + pBtMgnt->ExtConfig.bEnableWifiScanNotify = *((u8 *)pHciCmd->Data); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("bEnableWifiScanNotify = %d\n", pBtMgnt->ExtConfig.bEnableWifiScanNotify)); + + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_ENABLE_WIFI_SCAN_NOTIFY, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdWIFICurrentChannel(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u8 chnl = pmlmeext->cur_channel; + + if (pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) { + if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + chnl += 2; + else if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + chnl -= 2; + } + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Current Channel = 0x%x\n", chnl)); + + { + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_WIFI_CURRENT_CHANNEL, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = chnl; /* current channel */ + len += 2; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdWIFICurrentBandwidth(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + enum ht_channel_width bw; + u8 CurrentBW = 0; + + bw = padapter->mlmeextpriv.cur_bwmode; + + if (bw == HT_CHANNEL_WIDTH_20) + CurrentBW = 0; + else if (bw == HT_CHANNEL_WIDTH_40) + CurrentBW = 1; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Current BW = 0x%x\n", + CurrentBW)); + + { + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_WIFI_CURRENT_BANDWIDTH, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = CurrentBW; /* current BW */ + len += 2; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdWIFIConnectionStatus( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + u8 connectStatus = HCI_WIFI_NOT_CONNECTED; + + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) { + if (padapter->stapriv.asoc_sta_count >= 3) + connectStatus = HCI_WIFI_CONNECTED; + else + connectStatus = HCI_WIFI_NOT_CONNECTED; + } else if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_ASOC_STATE)) { + connectStatus = HCI_WIFI_CONNECTED; + } else if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) { + connectStatus = HCI_WIFI_CONNECT_IN_PROGRESS; + } else { + connectStatus = HCI_WIFI_NOT_CONNECTED; + } + + { + u8 localBuf[8] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_EXTENSION, + HCI_WIFI_CONNECTION_STATUS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + pRetPar[1] = connectStatus; /* connect status */ + len += 2; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdEnableDeviceUnderTestMode( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + + pBtHciInfo->bInTestMode = true; + pBtHciInfo->bTestIsEnd = false; + + /* send command complete event here when all data are received. */ + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_TESTING_COMMANDS, + HCI_ENABLE_DEVICE_UNDER_TEST_MODE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdAMPTestEnd(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 bFilterOutNonAssociatedBSSID = true; + + if (!pBtHciInfo->bInTestMode) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Not in Test mode, return status = HCI_STATUS_CMD_DISALLOW\n")); + status = HCI_STATUS_CMD_DISALLOW; + return status; + } + + pBtHciInfo->bTestIsEnd = true; + + del_timer_sync(&pBTInfo->BTTestSendPacketTimer); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID)); + + /* send command complete event here when all data are received. */ + { + u8 localBuf[4] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("AMP Test End Event \n")); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_AMP_TEST_END; + PPacketIrpEvent->Length = 2; + + PPacketIrpEvent->Data[0] = status; + PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); + } + + bthci_EventAMPReceiverReport(padapter, 0x01); + + return status; +} + +static enum hci_status +bthci_CmdAMPTestCommand(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + + if (!pBtHciInfo->bInTestMode) { + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Not in Test mode, return status = HCI_STATUS_CMD_DISALLOW\n")); + status = HCI_STATUS_CMD_DISALLOW; + return status; + } + + pBtHciInfo->TestScenario = *((u8 *)pHciCmd->Data); + + if (pBtHciInfo->TestScenario == 0x01) + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("TX Single Test \n")); + else if (pBtHciInfo->TestScenario == 0x02) + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Receive Frame Test \n")); + else + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("No Such Test !!!!!!!!!!!!!!!!!! \n")); + + if (pBtHciInfo->bTestIsEnd) { + u8 localBuf[5] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("AMP Test End Event \n")); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_AMP_TEST_END; + PPacketIrpEvent->Length = 2; + + PPacketIrpEvent->Data[0] = status; + PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario ; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); + + /* Return to Idel state with RX and TX off. */ + + return status; + } + + /* should send command status event */ + bthci_EventCommandStatus(padapter, + OGF_TESTING_COMMANDS, + HCI_AMP_TEST_COMMAND, + status); + + /* The HCI_AMP_Start Test Event shall be generated when the */ + /* HCI_AMP_Test_Command has completed and the first data is ready to be sent */ + /* or received. */ + + { + u8 localBuf[5] = ""; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), (" HCI_AMP_Start Test Event \n")); + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + PPacketIrpEvent->EventCode = HCI_EVENT_AMP_START_TEST; + PPacketIrpEvent->Length = 2; + + PPacketIrpEvent->Data[0] = status; + PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario ; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, 4); + + /* Return to Idel state with RX and TX off. */ + } + + if (pBtHciInfo->TestScenario == 0x01) { + /* + When in a transmitter test scenario and the frames/bursts count have been + transmitted the HCI_AMP_Test_End event shall be sent. + */ + mod_timer(&pBTInfo->BTTestSendPacketTimer, + jiffies + msecs_to_jiffies(50)); + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("TX Single Test \n")); + } else if (pBtHciInfo->TestScenario == 0x02) { + u8 bFilterOutNonAssociatedBSSID = false; + rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID)); + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Receive Frame Test \n")); + } + + return status; +} + +static enum hci_status +bthci_CmdEnableAMPReceiverReports(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + + if (!pBtHciInfo->bInTestMode) { + status = HCI_STATUS_CMD_DISALLOW; + /* send command complete event here when all data are received. */ + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_TESTING_COMMANDS, + HCI_ENABLE_AMP_RECEIVER_REPORTS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + return status; + } + + pBtHciInfo->bTestNeedReport = *((u8 *)pHciCmd->Data); + pBtHciInfo->TestReportInterval = (*((u8 *)pHciCmd->Data+2)); + + bthci_EventAMPReceiverReport(padapter, 0x00); + + /* send command complete event here when all data are received. */ + { + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_TESTING_COMMANDS, + HCI_ENABLE_AMP_RECEIVER_REPORTS, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + } + + return status; +} + +static enum hci_status +bthci_CmdHostBufferSize(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct packet_irp_hcievent_data *PPacketIrpEvent; + enum hci_status status = HCI_STATUS_SUCCESS; + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0; + + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].ACLPacketsData.ACLDataPacketLen = *((u16 *)pHciCmd->Data); + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].SyncDataPacketLen = *((u8 *)(pHciCmd->Data+2)); + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].TotalNumACLDataPackets = *((u16 *)(pHciCmd->Data+3)); + pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].TotalSyncNumDataPackets = *((u16 *)(pHciCmd->Data+5)); + + /* send command complete event here when all data are received. */ + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + len += bthci_CommandCompleteHeader(&localBuf[0], + OGF_SET_EVENT_MASK_COMMAND, + HCI_HOST_BUFFER_SIZE, + status); + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[len]; + pRetPar[0] = status; /* status */ + len += 1; + PPacketIrpEvent->Length = len; + + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); + + return status; +} + +static enum hci_status +bthci_CmdHostNumberOfCompletedPackets(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + return status; +} + +static enum hci_status +bthci_UnknownCMD(struct rtw_adapter *padapter, struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_UNKNOW_HCI_CMD; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + pBtDbg->dbgHciInfo.hciCmdCntUnknown++; + bthci_EventCommandStatus(padapter, + (u8)pHciCmd->OGF, + pHciCmd->OCF, + status); + + return status; +} + +static enum hci_status +bthci_HandleOGFInformationalParameters(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + switch (pHciCmd->OCF) { + case HCI_READ_LOCAL_VERSION_INFORMATION: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_VERSION_INFORMATION\n")); + status = bthci_CmdReadLocalVersionInformation(padapter); + break; + case HCI_READ_LOCAL_SUPPORTED_COMMANDS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_SUPPORTED_COMMANDS\n")); + status = bthci_CmdReadLocalSupportedCommands(padapter); + break; + case HCI_READ_LOCAL_SUPPORTED_FEATURES: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_SUPPORTED_FEATURES\n")); + status = bthci_CmdReadLocalSupportedFeatures(padapter); + break; + case HCI_READ_BUFFER_SIZE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_BUFFER_SIZE\n")); + status = bthci_CmdReadBufferSize(padapter); + break; + case HCI_READ_DATA_BLOCK_SIZE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_DATA_BLOCK_SIZE\n")); + status = bthci_CmdReadDataBlockSize(padapter); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFInformationalParameters(), Unknown case = 0x%x\n", pHciCmd->OCF)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static enum hci_status +bthci_HandleOGFSetEventMaskCMD(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + switch (pHciCmd->OCF) { + case HCI_SET_EVENT_MASK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_MASK\n")); + status = bthci_CmdSetEventMask(padapter, pHciCmd); + break; + case HCI_RESET: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_RESET\n")); + status = bthci_CmdReset(padapter, true); + break; + case HCI_READ_CONNECTION_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_CONNECTION_ACCEPT_TIMEOUT\n")); + status = bthci_CmdReadConnectionAcceptTimeout(padapter); + break; + case HCI_SET_EVENT_FILTER: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_FILTER\n")); + status = bthci_CmdSetEventFilter(padapter, pHciCmd); + break; + case HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT\n")); + status = bthci_CmdWriteConnectionAcceptTimeout(padapter, pHciCmd); + break; + case HCI_READ_PAGE_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_PAGE_TIMEOUT\n")); + status = bthci_CmdReadPageTimeout(padapter, pHciCmd); + break; + case HCI_WRITE_PAGE_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_PAGE_TIMEOUT\n")); + status = bthci_CmdWritePageTimeout(padapter, pHciCmd); + break; + case HCI_HOST_NUMBER_OF_COMPLETED_PACKETS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_HOST_NUMBER_OF_COMPLETED_PACKETS\n")); + status = bthci_CmdHostNumberOfCompletedPackets(padapter, pHciCmd); + break; + case HCI_READ_LINK_SUPERVISION_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LINK_SUPERVISION_TIMEOUT\n")); + status = bthci_CmdReadLinkSupervisionTimeout(padapter, pHciCmd); + break; + case HCI_WRITE_LINK_SUPERVISION_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LINK_SUPERVISION_TIMEOUT\n")); + status = bthci_CmdWriteLinkSupervisionTimeout(padapter, pHciCmd); + break; + case HCI_ENHANCED_FLUSH: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENHANCED_FLUSH\n")); + status = bthci_CmdEnhancedFlush(padapter, pHciCmd); + break; + case HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT\n")); + status = bthci_CmdReadLogicalLinkAcceptTimeout(padapter, pHciCmd); + break; + case HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT\n")); + status = bthci_CmdWriteLogicalLinkAcceptTimeout(padapter, pHciCmd); + break; + case HCI_SET_EVENT_MASK_PAGE_2: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_MASK_PAGE_2\n")); + status = bthci_CmdSetEventMaskPage2(padapter, pHciCmd); + break; + case HCI_READ_LOCATION_DATA: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCATION_DATA\n")); + status = bthci_CmdReadLocationData(padapter, pHciCmd); + break; + case HCI_WRITE_LOCATION_DATA: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LOCATION_DATA\n")); + status = bthci_CmdWriteLocationData(padapter, pHciCmd); + break; + case HCI_READ_FLOW_CONTROL_MODE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_FLOW_CONTROL_MODE\n")); + status = bthci_CmdReadFlowControlMode(padapter, pHciCmd); + break; + case HCI_WRITE_FLOW_CONTROL_MODE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_FLOW_CONTROL_MODE\n")); + status = bthci_CmdWriteFlowControlMode(padapter, pHciCmd); + break; + case HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT\n")); + status = bthci_CmdReadBestEffortFlushTimeout(padapter, pHciCmd); + break; + case HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT\n")); + status = bthci_CmdWriteBestEffortFlushTimeout(padapter, pHciCmd); + break; + case HCI_SHORT_RANGE_MODE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SHORT_RANGE_MODE\n")); + status = bthci_CmdShortRangeMode(padapter, pHciCmd); + break; + case HCI_HOST_BUFFER_SIZE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_HOST_BUFFER_SIZE\n")); + status = bthci_CmdHostBufferSize(padapter, pHciCmd); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFSetEventMaskCMD(), Unknown case = 0x%x\n", pHciCmd->OCF)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static enum hci_status +bthci_HandleOGFStatusParameters(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + switch (pHciCmd->OCF) { + case HCI_READ_FAILED_CONTACT_COUNTER: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_FAILED_CONTACT_COUNTER\n")); + status = bthci_CmdReadFailedContactCounter(padapter, pHciCmd); + break; + case HCI_RESET_FAILED_CONTACT_COUNTER: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_RESET_FAILED_CONTACT_COUNTER\n")); + status = bthci_CmdResetFailedContactCounter(padapter, pHciCmd); + break; + case HCI_READ_LINK_QUALITY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LINK_QUALITY\n")); + status = bthci_CmdReadLinkQuality(padapter, pHciCmd); + break; + case HCI_READ_RSSI: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_RSSI\n")); + status = bthci_CmdReadRSSI(padapter); + break; + case HCI_READ_LOCAL_AMP_INFO: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_AMP_INFO\n")); + status = bthci_CmdReadLocalAMPInfo(padapter); + break; + case HCI_READ_LOCAL_AMP_ASSOC: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_AMP_ASSOC\n")); + status = bthci_CmdReadLocalAMPAssoc(padapter, pHciCmd); + break; + case HCI_WRITE_REMOTE_AMP_ASSOC: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_REMOTE_AMP_ASSOC\n")); + status = bthci_CmdWriteRemoteAMPAssoc(padapter, pHciCmd); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFStatusParameters(), Unknown case = 0x%x\n", pHciCmd->OCF)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static enum hci_status +bthci_HandleOGFLinkControlCMD(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + + switch (pHciCmd->OCF) { + case HCI_CREATE_PHYSICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_CREATE_PHYSICAL_LINK\n")); + status = bthci_CmdCreatePhysicalLink(padapter, pHciCmd); + break; + case HCI_ACCEPT_PHYSICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ACCEPT_PHYSICAL_LINK\n")); + status = bthci_CmdAcceptPhysicalLink(padapter, pHciCmd); + break; + case HCI_DISCONNECT_PHYSICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_PHYSICAL_LINK\n")); + status = bthci_CmdDisconnectPhysicalLink(padapter, pHciCmd); + break; + case HCI_CREATE_LOGICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_CREATE_LOGICAL_LINK\n")); + status = bthci_CmdCreateLogicalLink(padapter, pHciCmd); + break; + case HCI_ACCEPT_LOGICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ACCEPT_LOGICAL_LINK\n")); + status = bthci_CmdAcceptLogicalLink(padapter, pHciCmd); + break; + case HCI_DISCONNECT_LOGICAL_LINK: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_LOGICAL_LINK\n")); + status = bthci_CmdDisconnectLogicalLink(padapter, pHciCmd); + break; + case HCI_LOGICAL_LINK_CANCEL: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_LOGICAL_LINK_CANCEL\n")); + status = bthci_CmdLogicalLinkCancel(padapter, pHciCmd); + break; + case HCI_FLOW_SPEC_MODIFY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_FLOW_SPEC_MODIFY\n")); + status = bthci_CmdFlowSpecModify(padapter, pHciCmd); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFLinkControlCMD(), Unknown case = 0x%x\n", pHciCmd->OCF)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static enum hci_status +bthci_HandleOGFTestingCMD(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + switch (pHciCmd->OCF) { + case HCI_ENABLE_DEVICE_UNDER_TEST_MODE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENABLE_DEVICE_UNDER_TEST_MODE\n")); + bthci_CmdEnableDeviceUnderTestMode(padapter, pHciCmd); + break; + case HCI_AMP_TEST_END: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_AMP_TEST_END\n")); + bthci_CmdAMPTestEnd(padapter, pHciCmd); + break; + case HCI_AMP_TEST_COMMAND: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_AMP_TEST_COMMAND\n")); + bthci_CmdAMPTestCommand(padapter, pHciCmd); + break; + case HCI_ENABLE_AMP_RECEIVER_REPORTS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENABLE_AMP_RECEIVER_REPORTS\n")); + bthci_CmdEnableAMPReceiverReports(padapter, pHciCmd); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static enum hci_status +bthci_HandleOGFExtension(struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + switch (pHciCmd->OCF) { + case HCI_SET_ACL_LINK_DATA_FLOW_MODE: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_ACL_LINK_DATA_FLOW_MODE\n")); + status = bthci_CmdSetACLLinkDataFlowMode(padapter, pHciCmd); + break; + case HCI_SET_ACL_LINK_STATUS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_ACL_LINK_STATUS\n")); + status = bthci_CmdSetACLLinkStatus(padapter, pHciCmd); + break; + case HCI_SET_SCO_LINK_STATUS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_SCO_LINK_STATUS\n")); + status = bthci_CmdSetSCOLinkStatus(padapter, pHciCmd); + break; + case HCI_SET_RSSI_VALUE: + RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL, ("HCI_SET_RSSI_VALUE\n")); + status = bthci_CmdSetRSSIValue(padapter, pHciCmd); + break; + case HCI_SET_CURRENT_BLUETOOTH_STATUS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_CURRENT_BLUETOOTH_STATUS\n")); + status = bthci_CmdSetCurrentBluetoothStatus(padapter, pHciCmd); + break; + /* The following is for RTK8723 */ + + case HCI_EXTENSION_VERSION_NOTIFY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_EXTENSION_VERSION_NOTIFY\n")); + status = bthci_CmdExtensionVersionNotify(padapter, pHciCmd); + break; + case HCI_LINK_STATUS_NOTIFY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_LINK_STATUS_NOTIFY\n")); + status = bthci_CmdLinkStatusNotify(padapter, pHciCmd); + break; + case HCI_BT_OPERATION_NOTIFY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_BT_OPERATION_NOTIFY\n")); + status = bthci_CmdBtOperationNotify(padapter, pHciCmd); + break; + case HCI_ENABLE_WIFI_SCAN_NOTIFY: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_ENABLE_WIFI_SCAN_NOTIFY\n")); + status = bthci_CmdEnableWifiScanNotify(padapter, pHciCmd); + break; + + /* The following is for IVT */ + case HCI_WIFI_CURRENT_CHANNEL: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CURRENT_CHANNEL\n")); + status = bthci_CmdWIFICurrentChannel(padapter, pHciCmd); + break; + case HCI_WIFI_CURRENT_BANDWIDTH: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CURRENT_BANDWIDTH\n")); + status = bthci_CmdWIFICurrentBandwidth(padapter, pHciCmd); + break; + case HCI_WIFI_CONNECTION_STATUS: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CONNECTION_STATUS\n")); + status = bthci_CmdWIFIConnectionStatus(padapter, pHciCmd); + break; + + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + return status; +} + +static void +bthci_StateStarting(struct rtw_adapter *padapter, + enum hci_state_with_cmd StateCmd, u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Starting], ")); + switch (StateCmd) { + case STATE_CMD_CONNECT_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n")); + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT; + pBtMgnt->bNeedNotifyAMPNoCap = true; + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID; + + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + case STATE_CMD_MAC_START_COMPLETE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_START_COMPLETE\n")); + if (pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_CREATOR) + bthci_EventChannelSelected(padapter, EntryNum); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +static void +bthci_StateConnecting(struct rtw_adapter *padapter, + enum hci_state_with_cmd StateCmd, u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Connecting], ")); + switch (StateCmd) { + case STATE_CMD_CONNECT_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n")); + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT; + pBtMgnt->bNeedNotifyAMPNoCap = true; + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + case STATE_CMD_MAC_CONNECT_COMPLETE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_COMPLETE\n")); + + if (pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_JOINER) { + RT_TRACE(_module_rtl871x_security_c_, + _drv_info_, ("StateConnecting \n")); + } + break; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID; + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + BTHCI_DisconnectPeer(padapter, EntryNum); + + break; + case STATE_CMD_MAC_CONNECT_CANCEL_INDICATE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_CANCEL_INDICATE\n")); + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONTROLLER_BUSY; + /* Because this state cmd is caused by the BTHCI_EventAMPStatusChange(), */ + /* we don't need to send event in the following BTHCI_DisconnectPeer() again. */ + pBtMgnt->bNeedNotifyAMPNoCap = false; + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +static void +bthci_StateConnected(struct rtw_adapter *padapter, + enum hci_state_with_cmd StateCmd, u8 EntryNum) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Connected], ")); + switch (StateCmd) { + u8 i; + u16 logicHandle = 0; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + + /* When we are trying to disconnect the phy link, we should disconnect log link first, */ + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle != 0) { + logicHandle = pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle; + + bthci_EventDisconnectLogicalLinkComplete(padapter, HCI_STATUS_SUCCESS, + logicHandle, pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason); + + pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle = 0; + } + } + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + + case STATE_CMD_MAC_DISCONNECT_INDICATE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_DISCONNECT_INDICATE\n")); + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + /* TODO: Remote Host not local host */ + HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST, + EntryNum); + BTHCI_DisconnectPeer(padapter, EntryNum); + + break; + case STATE_CMD_ENTER_STATE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ENTER_STATE\n")); + + if (pBtMgnt->bBTConnectInProgress) { + pBtMgnt->bBTConnectInProgress = false; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n")); + } + pBTInfo->BtAsocEntry[EntryNum].BtCurrentState = HCI_STATE_CONNECTED; + pBTInfo->BtAsocEntry[EntryNum].b4waySuccess = true; + pBtMgnt->bStartSendSupervisionPkt = true; + + /* for rate adaptive */ + + if (padapter->HalFunc.UpdateRAMaskHandler) + padapter->HalFunc.UpdateRAMaskHandler(padapter, MAX_FW_SUPPORT_MACID_NUM-1-EntryNum, 0); + + rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, padapter->mlmepriv.cur_network.network.SupportedRates); + BTDM_SetFwChnlInfo(padapter, RT_MEDIA_CONNECT); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +static void +bthci_StateAuth(struct rtw_adapter *padapter, enum hci_state_with_cmd StateCmd, + u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Authenticating], ")); + switch (StateCmd) { + case STATE_CMD_CONNECT_ACCEPT_TIMEOUT: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n")); + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT; + pBtMgnt->bNeedNotifyAMPNoCap = true; + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID; + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + case STATE_CMD_4WAY_FAILED: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_4WAY_FAILED\n")); + + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_AUTH_FAIL; + pBtMgnt->bNeedNotifyAMPNoCap = true; + + BTHCI_DisconnectPeer(padapter, EntryNum); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + break; + case STATE_CMD_4WAY_SUCCESSED: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_4WAY_SUCCESSED\n")); + + bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_SUCCESS, EntryNum, INVALID_PL_HANDLE); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTED, STATE_CMD_ENTER_STATE, EntryNum); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +static void +bthci_StateDisconnecting(struct rtw_adapter *padapter, + enum hci_state_with_cmd StateCmd, u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Disconnecting], ")); + switch (StateCmd) { + case STATE_CMD_MAC_CONNECT_CANCEL_INDICATE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_CANCEL_INDICATE\n")); + if (pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent) { + bthci_EventPhysicalLinkComplete(padapter, + pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus, + EntryNum, INVALID_PL_HANDLE); + } + + if (pBtMgnt->bBTConnectInProgress) { + pBtMgnt->bBTConnectInProgress = false; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n")); + } + + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ENTER_STATE, EntryNum); + break; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + BTHCI_DisconnectPeer(padapter, EntryNum); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +static void +bthci_StateDisconnected(struct rtw_adapter *padapter, + enum hci_state_with_cmd StateCmd, u8 EntryNum) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Disconnected], ")); + switch (StateCmd) { + case STATE_CMD_CREATE_PHY_LINK: + case STATE_CMD_ACCEPT_PHY_LINK: + if (StateCmd == STATE_CMD_CREATE_PHY_LINK) + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CREATE_PHY_LINK\n")); + else + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ACCEPT_PHY_LINK\n")); + + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT PS], Disable IPS and LPS\n")); + ips_leave23a(padapter); + LPS_Leave23a(padapter); + + pBtMgnt->bPhyLinkInProgress = true; + pBtMgnt->BTCurrentConnectType = BT_DISCONNECT; + pBtMgnt->CurrentBTConnectionCnt++; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], CurrentBTConnectionCnt = %d\n", + pBtMgnt->CurrentBTConnectionCnt)); + pBtMgnt->BtOperationOn = true; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], Bt Operation ON!! CurrentConnectEntryNum = %d\n", + pBtMgnt->CurrentConnectEntryNum)); + + if (pBtMgnt->bBTConnectInProgress) { + bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_CONTROLLER_BUSY, INVALID_ENTRY_NUM, pBtMgnt->BtCurrentPhyLinkhandle); + bthci_RemoveEntryByEntryNum(padapter, EntryNum); + return; + } + + if (StateCmd == STATE_CMD_CREATE_PHY_LINK) + pBTInfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_CREATOR; + else + pBTInfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_JOINER; + + /* 1. MAC not yet in selected channel */ + while (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)) { + RTPRINT(FIOCTL, IOCTL_STATE, ("Scan/Roaming/Wifi Link is in Progress, wait 200 ms\n")); + mdelay(200); + } + /* 2. MAC already in selected channel */ + RTPRINT(FIOCTL, IOCTL_STATE, ("Channel is Ready\n")); + mod_timer(&pBTInfo->BTHCIJoinTimeoutTimer, + jiffies + msecs_to_jiffies(pBtHciInfo->ConnAcceptTimeout)); + + pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent = true; + break; + case STATE_CMD_DISCONNECT_PHY_LINK: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); + + del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer); + + bthci_EventDisconnectPhyLinkComplete(padapter, + HCI_STATUS_SUCCESS, + pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason, + EntryNum); + + if (pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent) { + bthci_EventPhysicalLinkComplete(padapter, + HCI_STATUS_UNKNOW_CONNECT_ID, + EntryNum, INVALID_PL_HANDLE); + } + + if (pBtMgnt->bBTConnectInProgress) { + pBtMgnt->bBTConnectInProgress = false; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n")); + } + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ENTER_STATE, EntryNum); + bthci_RemoveEntryByEntryNum(padapter, EntryNum); + break; + case STATE_CMD_ENTER_STATE: + RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ENTER_STATE\n")); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd)); + break; + } +} + +void BTHCI_EventParse(struct rtw_adapter *padapter, void *pEvntData, u32 dataLen) +{ +} + +u8 BTHCI_HsConnectionEstablished(struct rtw_adapter *padapter) +{ + u8 bBtConnectionExist = false; + struct bt_30info *pBtinfo = GET_BT_INFO(padapter); + u8 i; + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + if (pBtinfo->BtAsocEntry[i].b4waySuccess) { + bBtConnectionExist = true; + break; + } + } + +/*RTPRINT(FIOCTL, IOCTL_STATE, (" BTHCI_HsConnectionEstablished(), connection exist = %d\n", bBtConnectionExist)); */ + + return bBtConnectionExist; +} + +static u8 +BTHCI_CheckProfileExist(struct rtw_adapter *padapter, + enum bt_traffic_mode_profile Profile) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 IsPRofile = false; + u8 i = 0; + + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + if (pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile == Profile) { + IsPRofile = true; + break; + } + } + + return IsPRofile; +} + +void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 i = 0; + + pBtMgnt->ExtConfig.NumberOfSCO = 0; + + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = BT_PROFILE_NONE; + + if (pBtMgnt->ExtConfig.linkInfo[i].BTProfile == BT_PROFILE_SCO) + pBtMgnt->ExtConfig.NumberOfSCO++; + + pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = pBtMgnt->ExtConfig.linkInfo[i].BTProfile; + switch (pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile) { + case BT_PROFILE_SCO: + break; + case BT_PROFILE_PAN: + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_BE; + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_BE; + break; + case BT_PROFILE_A2DP: + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_GULB; + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_GULB; + break; + case BT_PROFILE_HID: + pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_GUL; + pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_BE; + break; + default: + break; + } + } + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RTK, NumberOfHandle = %d, NumberOfSCO = %d\n", + pBtMgnt->ExtConfig.NumberOfHandle, pBtMgnt->ExtConfig.NumberOfSCO)); +} + +void BTHCI_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bEnableWifiScanNotify) + bthci_EventExtWifiScanNotify(padapter, scanType); +} + +void +BTHCI_StateMachine( + struct rtw_adapter *padapter, + u8 StateToEnter, + enum hci_state_with_cmd StateCmd, + u8 EntryNum + ) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (EntryNum == 0xff) { + RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, error EntryNum = 0x%x \n", EntryNum)); + return; + } + RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, EntryNum = 0x%x, CurrentState = 0x%x, BtNextState = 0x%x, StateCmd = 0x%x , StateToEnter = 0x%x\n", + EntryNum, pBTInfo->BtAsocEntry[EntryNum].BtCurrentState, pBTInfo->BtAsocEntry[EntryNum].BtNextState, StateCmd, StateToEnter)); + + if (pBTInfo->BtAsocEntry[EntryNum].BtNextState & StateToEnter) { + pBTInfo->BtAsocEntry[EntryNum].BtCurrentState = StateToEnter; + + switch (StateToEnter) { + case HCI_STATE_STARTING: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTING | HCI_STATE_CONNECTING; + bthci_StateStarting(padapter, StateCmd, EntryNum); + break; + case HCI_STATE_CONNECTING: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_CONNECTING | HCI_STATE_DISCONNECTING | HCI_STATE_AUTHENTICATING; + bthci_StateConnecting(padapter, StateCmd, EntryNum); + break; + case HCI_STATE_AUTHENTICATING: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTING | HCI_STATE_CONNECTED; + bthci_StateAuth(padapter, StateCmd, EntryNum); + break; + case HCI_STATE_CONNECTED: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_CONNECTED | HCI_STATE_DISCONNECTING; + bthci_StateConnected(padapter, StateCmd, EntryNum); + break; + case HCI_STATE_DISCONNECTING: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED | HCI_STATE_DISCONNECTING; + bthci_StateDisconnecting(padapter, StateCmd, EntryNum); + break; + case HCI_STATE_DISCONNECTED: + pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED | HCI_STATE_STARTING | HCI_STATE_CONNECTING; + bthci_StateDisconnected(padapter, StateCmd, EntryNum); + break; + default: + RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, Unknown state to enter!!!\n")); + break; + } + } else { + RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, Wrong state to enter\n")); + } + + /* 20100325 Joseph: Disable/Enable IPS/LPS according to BT status. */ + if (!pBtMgnt->bBTConnectInProgress && !pBtMgnt->BtOperationOn) { + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT PS], ips_enter23a()\n")); + ips_enter23a(padapter); + } +} + +void BTHCI_DisconnectPeer(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, (" BTHCI_DisconnectPeer()\n")); + + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, EntryNum); + + if (pBTInfo->BtAsocEntry[EntryNum].bUsed) { +/*BTPKT_SendDeauthentication(padapter, pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr, unspec_reason); not porting yet */ + } + + if (pBtMgnt->bBTConnectInProgress) { + pBtMgnt->bBTConnectInProgress = false; + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n")); + } + + bthci_RemoveEntryByEntryNum(padapter, EntryNum); + + if (pBtMgnt->bNeedNotifyAMPNoCap) { + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT AMPStatus], set to invalid in BTHCI_DisconnectPeer()\n")); + BTHCI_EventAMPStatusChange(padapter, AMP_STATUS_NO_CAPACITY_FOR_BT); + } +} + +void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo; + u8 localBuf[TmpLocalBufSize] = ""; + u8 *pRetPar, *pTriple; + u8 len = 0, i, j, handleNum = 0; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u16 *pu2Temp, *pPackets, *pHandle, *pDblocks; + u8 sent = 0; + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + + if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS)) { + RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Num Of Completed DataBlocks, Ignore to send NumOfCompletedDataBlocksEvent due to event mask page 2\n")); + return; + } + + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[0]; + pTriple = &pRetPar[3]; + for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) { + + for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) { + if (pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle) { + handleNum++; + pHandle = (u16 *)&pTriple[0]; /* Handle[i] */ + pPackets = (u16 *)&pTriple[2]; /* Num_Of_Completed_Packets[i] */ + pDblocks = (u16 *)&pTriple[4]; /* Num_Of_Completed_Blocks[i] */ + *pHandle = pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle; + *pPackets = (u16)pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount; + *pDblocks = (u16)pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount; + if (pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount) { + sent = 1; + RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL, + ("[BT event], Num Of Completed DataBlocks, Handle = 0x%x, Num_Of_Completed_Packets = 0x%x, Num_Of_Completed_Blocks = 0x%x\n", + *pHandle, *pPackets, *pDblocks)); + } + pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount = 0; + len += 6; + pTriple += len; + } + } + } + + pRetPar[2] = handleNum; /* Number_of_Handles */ + len += 1; + pu2Temp = (u16 *)&pRetPar[0]; + *pu2Temp = BTTotalDataBlockNum; + len += 2; + + PPacketIrpEvent->EventCode = HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS; + PPacketIrpEvent->Length = len; + if (handleNum && sent) + bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2); +} + +void BTHCI_EventAMPStatusChange(struct rtw_adapter *padapter, u8 AMP_Status) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct packet_irp_hcievent_data *PPacketIrpEvent; + u8 len = 0; + u8 localBuf[7] = ""; + u8 *pRetPar; + + if (AMP_Status == AMP_STATUS_NO_CAPACITY_FOR_BT) { + pBtMgnt->BTNeedAMPStatusChg = true; + pBtMgnt->bNeedNotifyAMPNoCap = false; + + BTHCI_DisconnectAll(padapter); + } else if (AMP_Status == AMP_STATUS_FULL_CAPACITY_FOR_BT) { + pBtMgnt->BTNeedAMPStatusChg = false; + } + + PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]); + /* Return parameters starts from here */ + pRetPar = &PPacketIrpEvent->Data[0]; + + pRetPar[0] = 0; /* Status */ + len += 1; + pRetPar[1] = AMP_Status; /* AMP_Status */ + len += 1; + + PPacketIrpEvent->EventCode = HCI_EVENT_AMP_STATUS_CHANGE; + PPacketIrpEvent->Length = len; + if (bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2) == RT_STATUS_SUCCESS) + RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_STATE), ("[BT event], AMP Status Change, AMP_Status = %d\n", AMP_Status)); +} + +void BTHCI_DisconnectAll(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + u8 i; + + RTPRINT(FIOCTL, IOCTL_STATE, (" DisconnectALL()\n")); + + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + if (pBTInfo->BtAsocEntry[i].b4waySuccess) { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTED, STATE_CMD_DISCONNECT_PHY_LINK, i); + } else if (pBTInfo->BtAsocEntry[i].bUsed) { + if (pBTInfo->BtAsocEntry[i].BtCurrentState == HCI_STATE_CONNECTING) { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, i); + } else if (pBTInfo->BtAsocEntry[i].BtCurrentState == HCI_STATE_DISCONNECTING) { + BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, i); + } + } + } +} + +enum hci_status +BTHCI_HandleHCICMD( + struct rtw_adapter *padapter, + struct packet_irp_hcicmd_data *pHciCmd + ) +{ + enum hci_status status = HCI_STATUS_SUCCESS; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("\n")); + RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI Command start, OGF = 0x%x, OCF = 0x%x, Length = 0x%x\n", + pHciCmd->OGF, pHciCmd->OCF, pHciCmd->Length)); + if (pHciCmd->Length) { + RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), "HCI Command, Hex Data :\n", + &pHciCmd->Data[0], pHciCmd->Length); + } + if (pHciCmd->OGF == OGF_EXTENSION) { + if (pHciCmd->OCF == HCI_SET_RSSI_VALUE) + RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL, ("[BT cmd], ")); + else + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[BT cmd], ")); + } else { + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("[BT cmd], ")); + } + + pBtDbg->dbgHciInfo.hciCmdCnt++; + + switch (pHciCmd->OGF) { + case LINK_CONTROL_COMMANDS: + status = bthci_HandleOGFLinkControlCMD(padapter, pHciCmd); + break; + case HOLD_MODE_COMMAND: + break; + case OGF_SET_EVENT_MASK_COMMAND: + status = bthci_HandleOGFSetEventMaskCMD(padapter, pHciCmd); + break; + case OGF_INFORMATIONAL_PARAMETERS: + status = bthci_HandleOGFInformationalParameters(padapter, pHciCmd); + break; + case OGF_STATUS_PARAMETERS: + status = bthci_HandleOGFStatusParameters(padapter, pHciCmd); + break; + case OGF_TESTING_COMMANDS: + status = bthci_HandleOGFTestingCMD(padapter, pHciCmd); + break; + case OGF_EXTENSION: + status = bthci_HandleOGFExtension(padapter, pHciCmd); + break; + default: + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI Command(), Unknown OGF = 0x%x\n", pHciCmd->OGF)); + RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n")); + status = bthci_UnknownCMD(padapter, pHciCmd); + break; + } + RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("HCI Command execution end!!\n")); + + return status; +} + +/* ===== End of sync from SD7 driver COMMOM/bt_hci.c ===== */ +#endif + +#ifdef __HALBTC87231ANT_C__ /* HAL/BTCoexist/HalBtc87231Ant.c */ + +static const char *const BtStateString[] = { + "BT_DISABLED", + "BT_NO_CONNECTION", + "BT_CONNECT_IDLE", + "BT_INQ_OR_PAG", + "BT_ACL_ONLY_BUSY", + "BT_SCO_ONLY_BUSY", + "BT_ACL_SCO_BUSY", + "BT_ACL_INQ_OR_PAG", + "BT_STATE_NOT_DEFINED" +}; + +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.c ===== */ + +static void btdm_SetFwIgnoreWlanAct(struct rtw_adapter *padapter, u8 bEnable) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[1] = {0}; + + if (bEnable) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Ignore Wlan_Act !!\n")); + H2C_Parameter[0] |= BIT(0); /* function enable */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT don't ignore Wlan_Act !!\n")); + } + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25 = 0x%02x\n", + H2C_Parameter[0])); + + FillH2CCmd(padapter, BT_IGNORE_WLAN_ACT_EID, 1, H2C_Parameter); +} + +static void btdm_NotifyFwScan(struct rtw_adapter *padapter, u8 scanType) +{ + u8 H2C_Parameter[1] = {0}; + + if (scanType == true) + H2C_Parameter[0] = 0x1; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Notify FW for wifi scan, write 0x3b = 0x%02x\n", + H2C_Parameter[0])); + + FillH2CCmd(padapter, 0x3b, 1, H2C_Parameter); +} + +static void btdm_1AntSetPSMode(struct rtw_adapter *padapter, + u8 enable, u8 smartps, u8 mode) +{ + struct pwrctrl_priv *pwrctrl; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Current LPS(%s, %d), smartps =%d\n", enable == true?"ON":"OFF", mode, smartps)); + + pwrctrl = &padapter->pwrctrlpriv; + + if (enable == true) { + rtw_set_ps_mode23a(padapter, PS_MODE_MIN, smartps, mode); + } else { + rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0); + LPS_RF_ON_check23a(padapter, 100); + } +} + +static void btdm_1AntTSFSwitch(struct rtw_adapter *padapter, u8 enable) +{ + u8 oldVal, newVal; + + oldVal = rtw_read8(padapter, 0x550); + + if (enable) + newVal = oldVal | EN_BCN_FUNCTION; + else + newVal = oldVal & ~EN_BCN_FUNCTION; + + if (oldVal != newVal) + rtw_write8(padapter, 0x550, newVal); +} + +static u8 btdm_Is1AntPsTdmaStateChange(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + + if ((pBtdm8723->bPrePsTdmaOn != pBtdm8723->bCurPsTdmaOn) || + (pBtdm8723->prePsTdma != pBtdm8723->curPsTdma)) + return true; + else + return false; +} + +/* Before enter TDMA, make sure Power Saving is enable! */ +static void +btdm_1AntPsTdma( + struct rtw_adapter *padapter, + u8 bTurnOn, + u8 type + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + + pBtdm8723->bCurPsTdmaOn = bTurnOn; + pBtdm8723->curPsTdma = type; + if (bTurnOn) { + switch (type) { + case 1: /* A2DP Level-1 or FTP/OPP */ + default: + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* wide duration for WiFi */ + BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x0, 0x58); + } + break; + case 2: /* A2DP Level-2 */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* normal duration for WiFi */ + BTDM_SetFw3a(padapter, 0xd3, 0x12, 0x12, 0x0, 0x58); + } + break; + case 3: /* BT FTP/OPP */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* normal duration for WiFi */ + BTDM_SetFw3a(padapter, 0xd3, 0x30, 0x03, 0x10, 0x58); + + } + break; + case 4: /* for wifi scan & BT is connected */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* protect 3 beacons in 3-beacon period & no Tx pause at BT slot */ + BTDM_SetFw3a(padapter, 0x93, 0x15, 0x03, 0x14, 0x0); + } + break; + case 5: /* for WiFi connected-busy & BT is Non-Connected-Idle */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* SCO mode, Ant fixed at WiFi, WLAN_Act toggle */ + BTDM_SetFw3a(padapter, 0x61, 0x15, 0x03, 0x31, 0x00); + } + break; + case 9: /* ACL high-retry type - 2 */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* narrow duration for WiFi */ + BTDM_SetFw3a(padapter, 0xd3, 0xa, 0xa, 0x0, 0x58); /* narrow duration for WiFi */ + } + break; + case 10: /* for WiFi connect idle & BT ACL busy or WiFi Connected-Busy & BT is Inquiry */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: /* ACL high-retry type - 3 */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* narrow duration for WiFi */ + BTDM_SetFw3a(padapter, 0xd3, 0x05, 0x05, 0x00, 0x58); + } + break; + case 12: /* for WiFi Connected-Busy & BT is Connected-Idle */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* Allow High-Pri BT */ + BTDM_SetFw3a(padapter, 0xeb, 0x0a, 0x03, 0x31, 0x18); + } + break; + case 20: /* WiFi only busy , TDMA mode for power saving */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0x13, 0x25, 0x25, 0x00, 0x00); + break; + case 27: /* WiFi DHCP/Site Survey & BT SCO busy */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xa3, 0x25, 0x03, 0x31, 0x98); + break; + case 28: /* WiFi DHCP/Site Survey & BT idle */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0x69, 0x25, 0x03, 0x31, 0x00); + break; + case 29: /* WiFi DHCP/Site Survey & BT ACL busy */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + BTDM_SetFw3a(padapter, 0xeb, 0x1a, 0x1a, 0x01, 0x18); + rtw_write32(padapter, 0x6c0, 0x5afa5afa); + rtw_write32(padapter, 0x6c4, 0x5afa5afa); + } + break; + case 30: /* WiFi idle & BT Inquiry */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0x93, 0x15, 0x03, 0x14, 0x00); + break; + case 31: /* BT HID */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x00, 0x58); + break; + case 32: /* BT SCO & Inquiry */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xab, 0x0a, 0x03, 0x11, 0x98); + break; + case 33: /* BT SCO & WiFi site survey */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xa3, 0x25, 0x03, 0x30, 0x98); + break; + case 34: /* BT HID & WiFi site survey */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x00, 0x18); + break; + case 35: /* BT HID & WiFi Connecting */ + if (btdm_Is1AntPsTdmaStateChange(padapter)) + BTDM_SetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x00, 0x18); + break; + } + } else { + /* disable PS-TDMA */ + switch (type) { + case 8: + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* Antenna control by PTA, 0x870 = 0x310 */ + BTDM_SetFw3a(padapter, 0x8, 0x0, 0x0, 0x0, 0x0); + } + break; + case 0: + default: + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* Antenna control by PTA, 0x870 = 0x310 */ + BTDM_SetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0); + } + rtw_write16(padapter, 0x860, 0x210); /* Switch Antenna to BT */ + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 0x860 = 0x210, Switch Antenna to BT\n")); + break; + case 9: + if (btdm_Is1AntPsTdmaStateChange(padapter)) { + /* Antenna control by PTA, 0x870 = 0x310 */ + BTDM_SetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0); + } + rtw_write16(padapter, 0x860, 0x110); /* Switch Antenna to WiFi */ + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 0x860 = 0x110, Switch Antenna to WiFi\n")); + break; + } + } + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Current TDMA(%s, %d)\n", + pBtdm8723->bCurPsTdmaOn?"ON":"OFF", pBtdm8723->curPsTdma)); + + /* update pre state */ + pBtdm8723->bPrePsTdmaOn = pBtdm8723->bCurPsTdmaOn; + pBtdm8723->prePsTdma = pBtdm8723->curPsTdma; +} + +static void +_btdm_1AntSetPSTDMA(struct rtw_adapter *padapter, u8 bPSEn, u8 smartps, + u8 psOption, u8 bTDMAOn, u8 tdmaType) +{ + struct pwrctrl_priv *pwrctrl; + struct hal_data_8723a *pHalData; + struct btdm_8723a_1ant *pBtdm8723; + u8 psMode; + u8 bSwitchPS; + + if (!check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) && + (get_fwstate(&padapter->mlmepriv) != WIFI_NULL_STATE)) { + btdm_1AntPsTdma(padapter, bTDMAOn, tdmaType); + return; + } + psOption &= ~BIT(0); + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], Set LPS(%s, %d) TDMA(%s, %d)\n", + bPSEn == true?"ON":"OFF", psOption, + bTDMAOn == true?"ON":"OFF", tdmaType)); + + pwrctrl = &padapter->pwrctrlpriv; + pHalData = GET_HAL_DATA(padapter); + pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + + if (bPSEn) { + if (pBtdm8723->bWiFiHalt) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi in Halt!!\n")); + return; + } + + if (pwrctrl->bInSuspend) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi in Suspend!!\n")); + return; + } + + if (padapter->bDriverStopped) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi driver stopped!!\n")); + return; + } + + if (padapter->bSurpriseRemoved) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi Surprise Removed!!\n")); + return; + } + + psMode = PS_MODE_MIN; + } else { + psMode = PS_MODE_ACTIVE; + psOption = 0; + } + + if (psMode != pwrctrl->pwr_mode) { + bSwitchPS = true; + } else if (psMode != PS_MODE_ACTIVE) { + if (psOption != pwrctrl->bcn_ant_mode) + bSwitchPS = true; + else if (smartps != pwrctrl->smart_ps) + bSwitchPS = true; + else + bSwitchPS = false; + } else { + bSwitchPS = false; + } + + if (bSwitchPS) { + /* disable TDMA */ + if (pBtdm8723->bCurPsTdmaOn) { + if (!bTDMAOn) { + btdm_1AntPsTdma(padapter, false, tdmaType); + } else { + if ((BT_IsBtDisabled(padapter)) || + (pHalData->bt_coexist.halCoex8723.c2hBtInfo == BT_INFO_STATE_NO_CONNECTION) || + (pHalData->bt_coexist.halCoex8723.c2hBtInfo == BT_INFO_STATE_CONNECT_IDLE) || + (tdmaType == 29)) + btdm_1AntPsTdma(padapter, false, 9); + else + btdm_1AntPsTdma(padapter, false, 0); + } + } + + /* change Power Save State */ + btdm_1AntSetPSMode(padapter, bPSEn, smartps, psOption); + } + + btdm_1AntPsTdma(padapter, bTDMAOn, tdmaType); +} + +static void +btdm_1AntSetPSTDMA(struct rtw_adapter *padapter, u8 bPSEn, + u8 psOption, u8 bTDMAOn, u8 tdmaType) +{ + _btdm_1AntSetPSTDMA(padapter, bPSEn, 0, psOption, bTDMAOn, tdmaType); +} + +static void btdm_1AntWifiParaAdjust(struct rtw_adapter *padapter, u8 bEnable) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + + if (bEnable) { + pBtdm8723->curWifiPara = 1; + if (pBtdm8723->preWifiPara != pBtdm8723->curWifiPara) + BTDM_SetSwPenaltyTxRateAdaptive(padapter, BT_TX_RATE_ADAPTIVE_LOW_PENALTY); + } else { + pBtdm8723->curWifiPara = 2; + if (pBtdm8723->preWifiPara != pBtdm8723->curWifiPara) + BTDM_SetSwPenaltyTxRateAdaptive(padapter, BT_TX_RATE_ADAPTIVE_NORMAL); + } + +} + +static void btdm_1AntPtaParaReload(struct rtw_adapter *padapter) +{ + /* PTA parameter */ + rtw_write8(padapter, 0x6cc, 0x0); /* 1-Ant coex */ + rtw_write32(padapter, 0x6c8, 0xffff); /* wifi break table */ + rtw_write32(padapter, 0x6c4, 0x55555555); /* coex table */ + + /* Antenna switch control parameter */ + rtw_write32(padapter, 0x858, 0xaaaaaaaa); + if (IS_8723A_A_CUT(GET_HAL_DATA(padapter)->VersionID)) { + rtw_write32(padapter, 0x870, 0x0); /* SPDT(connected with TRSW) control by hardware PTA */ + rtw_write8(padapter, 0x40, 0x24); + } else { + rtw_write8(padapter, 0x40, 0x20); + rtw_write16(padapter, 0x860, 0x210); /* set antenna at bt side if ANTSW is software control */ + rtw_write32(padapter, 0x870, 0x300); /* SPDT(connected with TRSW) control by hardware PTA */ + rtw_write32(padapter, 0x874, 0x22804000); /* ANTSW keep by GNT_BT */ + } + + /* coexistence parameters */ + rtw_write8(padapter, 0x778, 0x1); /* enable RTK mode PTA */ + + /* BT don't ignore WLAN_Act */ + btdm_SetFwIgnoreWlanAct(padapter, false); +} + +/* + * Return + *1: upgrade (add WiFi duration time) + *0: keep + *-1: downgrade (add BT duration time) + */ +static s8 btdm_1AntTdmaJudgement(struct rtw_adapter *padapter, u8 retry) +{ + struct hal_data_8723a *pHalData; + struct btdm_8723a_1ant *pBtdm8723; + static s8 up, dn, m = 1, n = 3, WaitCount; + s8 ret; + + pHalData = GET_HAL_DATA(padapter); + pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + ret = 0; + + if (pBtdm8723->psTdmaMonitorCnt == 0) { + up = 0; + dn = 0; + m = 1; + n = 3; + WaitCount = 0; + } else { + WaitCount++; + } + + if (retry == 0) { + /* no retry in the last 2-second duration */ + up++; + dn--; + if (dn < 0) + dn = 0; + if (up >= 3*m) { + /* retry = 0 in consecutive 3m*(2s), add WiFi duration */ + ret = 1; + + n = 3; + up = 0; + dn = 0; + WaitCount = 0; + } + } else if (retry <= 3) { + /* retry<= 3 in the last 2-second duration */ + up--; + dn++; + if (up < 0) + up = 0; + + if (dn == 2) { + /* retry<= 3 in consecutive 2*(2s), minus WiFi duration (add BT duration) */ + ret = -1; + + /* record how many time downgrad WiFi duration */ + if (WaitCount <= 2) + m++; + else + m = 1; + /* the max number of m is 20 */ + /* the longest time of upgrade WiFi duration is 20*3*2s = 120s */ + if (m >= 20) + m = 20; + up = 0; + dn = 0; + WaitCount = 0; + } + } else { + /* retry count > 3 */ + /* retry>3, minus WiFi duration (add BT duration) */ + ret = -1; + + /* record how many time downgrad WiFi duration */ + if (WaitCount == 1) + m++; + else + m = 1; + if (m >= 20) + m = 20; + + up = 0; + dn = 0; + WaitCount = 0; + } + return ret; +} + +static void btdm_1AntTdmaDurationAdjustForACL(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + + if (pBtdm8723->psTdmaGlobalCnt != pBtdm8723->psTdmaMonitorCnt) { + pBtdm8723->psTdmaMonitorCnt = 0; + pBtdm8723->psTdmaGlobalCnt = 0; + } + if (pBtdm8723->psTdmaMonitorCnt == 0) { + btdm_1AntSetPSTDMA(padapter, true, 0, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else { + /* Now we only have 4 level Ps Tdma, */ + /* if that's not the following 4 level(will changed by wifi scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if ((pBtdm8723->curPsTdma != 1) && + (pBtdm8723->curPsTdma != 2) && + (pBtdm8723->curPsTdma != 9) && + (pBtdm8723->curPsTdma != 11)) { + btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType); + } else { + s32 judge = 0; + + judge = btdm_1AntTdmaJudgement(padapter, pHalData->bt_coexist.halCoex8723.btRetryCnt); + if (judge == -1) { + if (pBtdm8723->curPsTdma == 1) { + /* Decrease WiFi duration for high BT retry */ + if (pHalData->bt_coexist.halCoex8723.btInfoExt) + pBtdm8723->psTdmaDuAdjType = 9; + else + pBtdm8723->psTdmaDuAdjType = 2; + btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType); + } else if (pBtdm8723->curPsTdma == 2) { + btdm_1AntSetPSTDMA(padapter, true, 0, true, 9); + pBtdm8723->psTdmaDuAdjType = 9; + } else if (pBtdm8723->curPsTdma == 9) { + btdm_1AntSetPSTDMA(padapter, true, 0, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } + } else if (judge == 1) { + if (pBtdm8723->curPsTdma == 11) { + btdm_1AntSetPSTDMA(padapter, true, 0, true, 9); + pBtdm8723->psTdmaDuAdjType = 9; + } else if (pBtdm8723->curPsTdma == 9) { + if (pHalData->bt_coexist.halCoex8723.btInfoExt) + pBtdm8723->psTdmaDuAdjType = 9; + else + pBtdm8723->psTdmaDuAdjType = 2; + btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType); + } else if (pBtdm8723->curPsTdma == 2) { + if (pHalData->bt_coexist.halCoex8723.btInfoExt) + pBtdm8723->psTdmaDuAdjType = 9; + else + pBtdm8723->psTdmaDuAdjType = 1; + btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType); + } + } + } + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], ACL current TDMA(%s, %d)\n", + (pBtdm8723->bCurPsTdmaOn ? "ON" : "OFF"), pBtdm8723->curPsTdma)); + } + pBtdm8723->psTdmaMonitorCnt++; +} + +static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv; + struct hal_data_8723a *pHalData; + struct bt_coexist_8723a *pBtCoex; + struct btdm_8723a_1ant *pBtdm8723; + u8 BtState; + + pmlmepriv = &padapter->mlmepriv; + pHalData = GET_HAL_DATA(padapter); + pBtCoex = &pHalData->bt_coexist.halCoex8723; + pBtdm8723 = &pBtCoex->btdm1Ant; + BtState = pBtCoex->c2hBtInfo; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is %s\n", BtStateString[BtState])); + + padapter->pwrctrlpriv.btcoex_rfon = false; + + if ((!BTDM_IsWifiBusy(padapter)) && (!check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) && + ((BtState == BT_INFO_STATE_NO_CONNECTION) || (BtState == BT_INFO_STATE_CONNECT_IDLE))) { + switch (BtState) { + case BT_INFO_STATE_NO_CONNECTION: + _btdm_1AntSetPSTDMA(padapter, true, 2, 0x26, false, 9); + break; + case BT_INFO_STATE_CONNECT_IDLE: + _btdm_1AntSetPSTDMA(padapter, true, 2, 0x26, false, 0); + break; + } + } else { + switch (BtState) { + case BT_INFO_STATE_NO_CONNECTION: + case BT_INFO_STATE_CONNECT_IDLE: + /* WiFi is Busy */ + btdm_1AntSetPSTDMA(padapter, false, 0, true, 5); + rtw_write32(padapter, 0x6c0, 0x5a5a5a5a); + rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); + break; + case BT_INFO_STATE_ACL_INQ_OR_PAG: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is BT_INFO_STATE_ACL_INQ_OR_PAG\n")); + case BT_INFO_STATE_INQ_OR_PAG: + padapter->pwrctrlpriv.btcoex_rfon = true; + btdm_1AntSetPSTDMA(padapter, true, 0, true, 30); + break; + case BT_INFO_STATE_SCO_ONLY_BUSY: + case BT_INFO_STATE_ACL_SCO_BUSY: + if (true == pBtCoex->bC2hBtInquiryPage) { + btdm_1AntSetPSTDMA(padapter, false, 0, true, 32); + } else { +#ifdef BTCOEX_CMCC_TEST + btdm_1AntSetPSTDMA(padapter, false, 0, true, 23); +#else /* !BTCOEX_CMCC_TEST */ + btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); + rtw_write32(padapter, 0x6c0, 0x5a5a5a5a); + rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); +#endif /* !BTCOEX_CMCC_TEST */ + } + break; + case BT_INFO_STATE_ACL_ONLY_BUSY: + padapter->pwrctrlpriv.btcoex_rfon = true; + if (pBtCoex->c2hBtProfile == BT_INFO_HID) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is HID\n")); + btdm_1AntSetPSTDMA(padapter, true, 0, true, 31); + } else if (pBtCoex->c2hBtProfile == BT_INFO_FTP) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is FTP/OPP\n")); + btdm_1AntSetPSTDMA(padapter, true, 0, true, 3); + } else if (pBtCoex->c2hBtProfile == (BT_INFO_A2DP|BT_INFO_FTP)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP_FTP\n")); + btdm_1AntSetPSTDMA(padapter, true, 0, true, 11); + } else { + if (pBtCoex->c2hBtProfile == BT_INFO_A2DP) + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP\n")); + else + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is UNKNOWN(0x%02X)! Use A2DP Profile\n", pBtCoex->c2hBtProfile)); + btdm_1AntTdmaDurationAdjustForACL(padapter); + } + break; + } + } + + pBtdm8723->psTdmaGlobalCnt++; +} + +static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u32 filter) +{ + u8 init_rate = 0; + u8 raid; + u32 mask; + u8 shortGIrate = false; + int supportRateNum = 0; + struct sta_info *psta; + struct hal_data_8723a *pHalData; + struct dm_priv *pdmpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + struct wlan_bssid_ex *cur_network; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d, filter = 0x%08x!!\n", __func__, mac_id, filter)); + + pHalData = GET_HAL_DATA(padapter); + pdmpriv = &pHalData->dmpriv; + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + cur_network = &pmlmeinfo->network; + + if (mac_id >= NUM_STA) { /* CAM_SIZE */ + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d illegal!!\n", __func__, mac_id)); + return; + } + + psta = pmlmeinfo->FW_sta_info[mac_id].psta; + if (psta == NULL) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, Can't find station!!\n", __func__)); + return; + } + + raid = psta->raid; + + switch (mac_id) { + case 0:/* for infra mode */ + supportRateNum = rtw_get_rateset_len23a(cur_network->SupportedRates); + mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum); + mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate23a(&pmlmeinfo->HT_caps):0; + if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps)) + shortGIrate = true; + break; + case 1:/* for broadcast/multicast */ + supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + mask = update_basic_rate23a(cur_network->SupportedRates, supportRateNum); + break; + default: /* for each sta in IBSS */ + supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum); + break; + } + mask |= ((raid<<28)&0xf0000000); + mask &= 0xffffffff; + mask &= ~filter; + init_rate = get_highest_rate_idx23a(mask)&0x3f; + + if (pHalData->fw_ractrl) { + u8 arg = 0; + + arg = mac_id&0x1f;/* MACID */ + arg |= BIT(7); + if (true == shortGIrate) + arg |= BIT(5); + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], Update FW RAID entry, MASK = 0x%08x, arg = 0x%02x\n", + mask, arg)); + + rtl8723a_set_raid_cmd(padapter, mask, arg); + } else { + if (shortGIrate) + init_rate |= BIT(6); + + rtw_write8(padapter, (REG_INIDATA_RATE_SEL+mac_id), init_rate); + } + + psta->init_rate = init_rate; + pdmpriv->INIDATA_RATE[mac_id] = init_rate; +} + +static void btdm_1AntUpdateHalRAMaskForSCO(struct rtw_adapter *padapter, u8 forceUpdate) +{ + struct btdm_8723a_1ant *pBtdm8723; + struct sta_priv *pstapriv; + struct wlan_bssid_ex *cur_network; + struct sta_info *psta; + u32 macid; + u32 filter = 0; + + pBtdm8723 = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant; + + if ((pBtdm8723->bRAChanged == true) && (forceUpdate == false)) + return; + + pstapriv = &padapter->stapriv; + cur_network = &padapter->mlmeextpriv.mlmext_info.network; + psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress); + macid = psta->mac_id; + + filter |= BIT(_1M_RATE_); + filter |= BIT(_2M_RATE_); + filter |= BIT(_5M_RATE_); + filter |= BIT(_11M_RATE_); + filter |= BIT(_6M_RATE_); + filter |= BIT(_9M_RATE_); + + btdm_1AntUpdateHalRAMask(padapter, macid, filter); + + pBtdm8723->bRAChanged = true; +} + +static void btdm_1AntRecoverHalRAMask(struct rtw_adapter *padapter) +{ + struct btdm_8723a_1ant *pBtdm8723; + struct sta_priv *pstapriv; + struct wlan_bssid_ex *cur_network; + struct sta_info *psta; + + pBtdm8723 = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant; + + if (pBtdm8723->bRAChanged == false) + return; + + pstapriv = &padapter->stapriv; + cur_network = &padapter->mlmeextpriv.mlmext_info.network; + psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress); + + Update_RA_Entry23a(padapter, psta); + + pBtdm8723->bRAChanged = false; +} + +static void +btdm_1AntBTStateChangeHandler(struct rtw_adapter *padapter, + enum bt_state_1ant oldState, enum bt_state_1ant newState) +{ + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT state change, %s => %s\n", BtStateString[oldState], BtStateString[newState])); + + /* BT default ignore wlan active, */ + /* WiFi MUST disable this when BT is enable */ + if (newState > BT_INFO_STATE_DISABLED) + btdm_SetFwIgnoreWlanAct(padapter, false); + + if ((check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) && + (BTDM_IsWifiConnectionExist(padapter))) { + if ((newState == BT_INFO_STATE_SCO_ONLY_BUSY) || + (newState == BT_INFO_STATE_ACL_SCO_BUSY)) { + btdm_1AntUpdateHalRAMaskForSCO(padapter, false); + } else { + /* Recover original RA setting */ + btdm_1AntRecoverHalRAMask(padapter); + } + } else { + GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bRAChanged = false; + } + + if (oldState == newState) + return; + + if (oldState == BT_INFO_STATE_ACL_ONLY_BUSY) { + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCnt = 0; + pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; + } + + if ((oldState == BT_INFO_STATE_SCO_ONLY_BUSY) || + (oldState == BT_INFO_STATE_ACL_SCO_BUSY)) { + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0; + } + + /* Active 2Ant mechanism when BT Connected */ + if ((oldState == BT_INFO_STATE_DISABLED) || + (oldState == BT_INFO_STATE_NO_CONNECTION)) { + if ((newState != BT_INFO_STATE_DISABLED) && + (newState != BT_INFO_STATE_NO_CONNECTION)) { + BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_SHRINK); + BTDM_AGCTable(padapter, BT_AGCTABLE_ON); + BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_ON); + } + } else { + if ((newState == BT_INFO_STATE_DISABLED) || + (newState == BT_INFO_STATE_NO_CONNECTION)) { + BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_RESUME); + BTDM_AGCTable(padapter, BT_AGCTABLE_OFF); + BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_OFF); + } + } +} + +static void btdm_1AntBtCoexistHandler(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_coexist_8723a *pBtCoex8723; + struct btdm_8723a_1ant *pBtdm8723; + + pHalData = GET_HAL_DATA(padapter); + pBtCoex8723 = &pHalData->bt_coexist.halCoex8723; + pBtdm8723 = &pBtCoex8723->btdm1Ant; + padapter->pwrctrlpriv.btcoex_rfon = false; + if (BT_IsBtDisabled(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is disabled\n")); + + if (BTDM_IsWifiConnectionExist(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n")); + + if (BTDM_IsWifiBusy(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is busy\n")); + btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is idle\n")); + _btdm_1AntSetPSTDMA(padapter, true, 2, 1, false, 9); + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n")); + + btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is enabled\n")); + + if (BTDM_IsWifiConnectionExist(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n")); + + btdm_1AntWifiParaAdjust(padapter, true); + btdm_1AntCoexProcessForWifiConnect(padapter); + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n")); + + /* Antenna switch at BT side(0x870 = 0x300, 0x860 = 0x210) after PSTDMA off */ + btdm_1AntWifiParaAdjust(padapter, false); + btdm_1AntSetPSTDMA(padapter, false, 0, false, 0); + } + } + + btdm_1AntBTStateChangeHandler(padapter, pBtCoex8723->prec2hBtInfo, pBtCoex8723->c2hBtInfo); + pBtCoex8723->prec2hBtInfo = pBtCoex8723->c2hBtInfo; +} + +void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt) +{ + struct hal_data_8723a *pHalData; + struct btdm_8723a_1ant *pBtdm8723; + u8 RSSI_WiFi_Cmpnstn, RSSI_BT_Cmpnstn; + + pHalData = GET_HAL_DATA(padapter); + pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant; + RSSI_WiFi_Cmpnstn = 0; + RSSI_BT_Cmpnstn = 0; + + switch (pBtdm8723->curPsTdma) { + case 1: /* WiFi 52ms */ + RSSI_WiFi_Cmpnstn = 11; /* 22*0.48 */ + break; + case 2: /* WiFi 36ms */ + RSSI_WiFi_Cmpnstn = 14; /* 22*0.64 */ + break; + case 9: /* WiFi 20ms */ + RSSI_WiFi_Cmpnstn = 18; /* 22*0.80 */ + break; + case 11: /* WiFi 10ms */ + RSSI_WiFi_Cmpnstn = 20; /* 22*0.90 */ + break; + case 4: /* WiFi 21ms */ + RSSI_WiFi_Cmpnstn = 17; /* 22*0.79 */ + break; + case 16: /* WiFi 24ms */ + RSSI_WiFi_Cmpnstn = 18; /* 22*0.76 */ + break; + case 18: /* WiFi 37ms */ + RSSI_WiFi_Cmpnstn = 14; /* 22*0.64 */ + break; + case 23: /* Level-1, Antenna switch to BT at all time */ + case 24: /* Level-2, Antenna switch to BT at all time */ + case 25: /* Level-3a, Antenna switch to BT at all time */ + case 26: /* Level-3b, Antenna switch to BT at all time */ + case 27: /* Level-3b, Antenna switch to BT at all time */ + case 33: /* BT SCO & WiFi site survey */ + RSSI_WiFi_Cmpnstn = 22; + break; + default: + break; + } + + if (rssi_wifi && RSSI_WiFi_Cmpnstn) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, WiFiCmpnstn =%d(%d => %d)\n", + pBtdm8723->curPsTdma, RSSI_WiFi_Cmpnstn, *rssi_wifi, *rssi_wifi+RSSI_WiFi_Cmpnstn)); + *rssi_wifi += RSSI_WiFi_Cmpnstn; + } + + if (rssi_bt && RSSI_BT_Cmpnstn) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, BTCmpnstn =%d(%d => %d)\n", + pBtdm8723->curPsTdma, RSSI_BT_Cmpnstn, *rssi_bt, *rssi_bt+RSSI_BT_Cmpnstn)); + *rssi_bt += RSSI_BT_Cmpnstn; + } +} + +static void BTDM_1AntParaInit(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_coexist_8723a *pBtCoex; + struct btdm_8723a_1ant *pBtdm8723; + + pHalData = GET_HAL_DATA(padapter); + pBtCoex = &pHalData->bt_coexist.halCoex8723; + pBtdm8723 = &pBtCoex->btdm1Ant; + + /* Enable counter statistics */ + rtw_write8(padapter, 0x76e, 0x4); + btdm_1AntPtaParaReload(padapter); + + pBtdm8723->wifiRssiThresh = 48; + + pBtdm8723->bWiFiHalt = false; + pBtdm8723->bRAChanged = false; + + if ((pBtCoex->c2hBtInfo != BT_INFO_STATE_DISABLED) && + (pBtCoex->c2hBtInfo != BT_INFO_STATE_NO_CONNECTION)) { + BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_SHRINK); + BTDM_AGCTable(padapter, BT_AGCTABLE_ON); + BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_ON); + } +} + +static void BTDM_1AntForHalt(struct rtw_adapter *padapter) +{ + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for halt\n")); + + GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true; + + btdm_1AntWifiParaAdjust(padapter, false); + + /* don't use btdm_1AntSetPSTDMA() here */ + /* it will call rtw_set_ps_mode23a() and request pwrpriv->lock. */ + /* This will lead to deadlock, if this function is called in IPS */ + /* Lucas@20130205 */ + btdm_1AntPsTdma(padapter, false, 0); + + btdm_SetFwIgnoreWlanAct(padapter, true); +} + +static void BTDM_1AntLpsLeave(struct rtw_adapter *padapter) +{ + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for LPS Leave\n")); + + /* Prevent from entering LPS again */ + GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true; + + btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); +/*btdm_1AntPsTdma(padapter, false, 8); */ +} + +static void BTDM_1AntWifiAssociateNotify(struct rtw_adapter *padapter, u8 type) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for associate, type =%d\n", type)); + + if (type) { + rtl8723a_CheckAntenna_Selection(padapter); + if (BT_IsBtDisabled(padapter)) { + btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); + } else { + struct bt_coexist_8723a *pBtCoex; + u8 BtState; + + pBtCoex = &pHalData->bt_coexist.halCoex8723; + BtState = pBtCoex->c2hBtInfo; + + btdm_1AntTSFSwitch(padapter, true); + + if ((BtState == BT_INFO_STATE_NO_CONNECTION) || + (BtState == BT_INFO_STATE_CONNECT_IDLE)) { + btdm_1AntSetPSTDMA(padapter, false, 0, true, 28); + } else if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) || + (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) { + btdm_1AntSetPSTDMA(padapter, false, 0, false, 8); + rtw_write32(padapter, 0x6c0, 0x5a5a5a5a); + rtw_write32(padapter, 0x6c4, 0x5a5a5a5a); + } else if ((BtState == BT_INFO_STATE_ACL_ONLY_BUSY) || + (BtState == BT_INFO_STATE_ACL_INQ_OR_PAG)) { + if (pBtCoex->c2hBtProfile == BT_INFO_HID) + btdm_1AntSetPSTDMA(padapter, false, 0, true, 35); + else + btdm_1AntSetPSTDMA(padapter, false, 0, true, 29); + } + } + } else { + if (BT_IsBtDisabled(padapter)) { + if (!BTDM_IsWifiConnectionExist(padapter)) { + btdm_1AntPsTdma(padapter, false, 0); + btdm_1AntTSFSwitch(padapter, false); + } + } + + btdm_1AntBtCoexistHandler(padapter); + } +} + +static void +BTDM_1AntMediaStatusNotify(struct rtw_adapter *padapter, + enum rt_media_status mstatus) +{ + struct bt_coexist_8723a *pBtCoex; + + pBtCoex = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723; + + RTPRINT(FBT, BT_TRACE, ("\n\n[BTCoex]******************************\n")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], MediaStatus, WiFi %s !!\n", + mstatus == RT_MEDIA_CONNECT?"CONNECT":"DISCONNECT")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex]******************************\n")); + + if (RT_MEDIA_CONNECT == mstatus) { + if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) { + if ((pBtCoex->c2hBtInfo == BT_INFO_STATE_SCO_ONLY_BUSY) || + (pBtCoex->c2hBtInfo == BT_INFO_STATE_ACL_SCO_BUSY)) + btdm_1AntUpdateHalRAMaskForSCO(padapter, true); + } + + padapter->pwrctrlpriv.DelayLPSLastTimeStamp = jiffies; + BTDM_1AntForDhcp(padapter); + } else { + /* DBG_8723A("%s rtl8723a_DeinitAntenna_Selection\n", __func__); */ + rtl8723a_DeinitAntenna_Selection(padapter); + btdm_1AntBtCoexistHandler(padapter); + pBtCoex->btdm1Ant.bRAChanged = false; + } +} + +void BTDM_1AntForDhcp(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + u8 BtState; + struct bt_coexist_8723a *pBtCoex; + struct btdm_8723a_1ant *pBtdm8723; + + pHalData = GET_HAL_DATA(padapter); + pBtCoex = &pHalData->bt_coexist.halCoex8723; + BtState = pBtCoex->c2hBtInfo; + pBtdm8723 = &pBtCoex->btdm1Ant; + + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for DHCP\n")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, %s\n", BtStateString[BtState])); + + BTDM_1AntWifiAssociateNotify(padapter, true); +} + +static void BTDM_1AntWifiScanNotify(struct rtw_adapter *padapter, u8 scanType) +{ + struct hal_data_8723a *pHalData; + u8 BtState; + struct bt_coexist_8723a *pBtCoex; + struct btdm_8723a_1ant *pBtdm8723; + + pHalData = GET_HAL_DATA(padapter); + BtState = pHalData->bt_coexist.halCoex8723.c2hBtInfo; + pBtCoex = &pHalData->bt_coexist.halCoex8723; + pBtdm8723 = &pBtCoex->btdm1Ant; + + RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for wifi scan =%d!!\n", scanType)); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE")); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, %s\n", BtStateString[BtState])); + + if (scanType) { + rtl8723a_CheckAntenna_Selection(padapter); + if (BT_IsBtDisabled(padapter)) { + btdm_1AntSetPSTDMA(padapter, false, 0, false, 9); + } else if (BTDM_IsWifiConnectionExist(padapter) == false) { + BTDM_1AntWifiAssociateNotify(padapter, true); + } else { + if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) || + (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) { + if (pBtCoex->bC2hBtInquiryPage) { + btdm_1AntSetPSTDMA(padapter, false, 0, true, 32); + } else { + padapter->pwrctrlpriv.btcoex_rfon = true; + btdm_1AntSetPSTDMA(padapter, true, 0, true, 33); + } + } else if (true == pBtCoex->bC2hBtInquiryPage) { + padapter->pwrctrlpriv.btcoex_rfon = true; + btdm_1AntSetPSTDMA(padapter, true, 0, true, 30); + } else if (BtState == BT_INFO_STATE_ACL_ONLY_BUSY) { + padapter->pwrctrlpriv.btcoex_rfon = true; + if (pBtCoex->c2hBtProfile == BT_INFO_HID) + btdm_1AntSetPSTDMA(padapter, true, 0, true, 34); + else + btdm_1AntSetPSTDMA(padapter, true, 0, true, 4); + } else { + padapter->pwrctrlpriv.btcoex_rfon = true; + btdm_1AntSetPSTDMA(padapter, true, 0, true, 5); + } + } + + btdm_NotifyFwScan(padapter, 1); + } else { + /* WiFi_Finish_Scan */ + btdm_NotifyFwScan(padapter, 0); + btdm_1AntBtCoexistHandler(padapter); + } +} + +static void BTDM_1AntFwC2hBtInfo8723A(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_coexist_8723a *pBtCoex; + u8 u1tmp, btState; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtCoex = &pHalData->bt_coexist.halCoex8723; + + u1tmp = pBtCoex->c2hBtInfoOriginal; + /* sco BUSY bit is not used on voice over PCM platform */ + btState = u1tmp & 0xF; + pBtCoex->c2hBtProfile = u1tmp & 0xE0; + + /* default set bt to idle state. */ + pBtMgnt->ExtConfig.bBTBusy = false; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE; + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (btState & BIT(2)) + pBtCoex->bC2hBtInquiryPage = true; + else + pBtCoex->bC2hBtInquiryPage = false; + btState &= ~BIT(2); + + if (!(btState & BIT(0))) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION; + } else { + if (btState == 0x1) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_CONNECT_IDLE; + } else if (btState == 0x9) { + if (pBtCoex->bC2hBtInquiryPage == true) + pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_INQ_OR_PAG; + else + pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_ONLY_BUSY; + pBtMgnt->ExtConfig.bBTBusy = true; + } else if (btState == 0x3) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_SCO_ONLY_BUSY; + pBtMgnt->ExtConfig.bBTBusy = true; + } else if (btState == 0xb) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_SCO_BUSY; + pBtMgnt->ExtConfig.bBTBusy = true; + } else { + pBtCoex->c2hBtInfo = BT_INFO_STATE_MAX; + } + if (pBtMgnt->ExtConfig.bBTBusy) + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_IDLE; + } + + if ((BT_INFO_STATE_NO_CONNECTION == pBtCoex->c2hBtInfo) || + (BT_INFO_STATE_CONNECT_IDLE == pBtCoex->c2hBtInfo)) { + if (pBtCoex->bC2hBtInquiryPage) + pBtCoex->c2hBtInfo = BT_INFO_STATE_INQ_OR_PAG; + } + + RTPRINT(FBT, BT_TRACE, ("[BTC2H], %s(%d)\n", + BtStateString[pBtCoex->c2hBtInfo], pBtCoex->c2hBtInfo)); + + if (pBtCoex->c2hBtProfile != BT_INFO_HID) + pBtCoex->c2hBtProfile &= ~BT_INFO_HID; +} + +void BTDM_1AntBtCoexist8723A(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv; + struct hal_data_8723a *pHalData; + unsigned long delta_time; + + pmlmepriv = &padapter->mlmepriv; + pHalData = GET_HAL_DATA(padapter); + + if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)) { + /* already done in BTDM_1AntForScan() */ + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under scan progress!!\n")); + return; + } + + if (check_fwstate(pmlmepriv, WIFI_UNDER_LINKING)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under link progress!!\n")); + return; + } + + /* under DHCP(Special packet) */ + delta_time = jiffies - padapter->pwrctrlpriv.DelayLPSLastTimeStamp; + delta_time = jiffies_to_msecs(delta_time); + if (delta_time < 500) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under DHCP " + "progress(%li ms)!!\n", delta_time)); + return; + } + + BTDM_CheckWiFiState(padapter); + + btdm_1AntBtCoexistHandler(padapter); +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.c ===== */ +#endif + +#ifdef __HALBTC87232ANT_C__ /* HAL/BTCoexist/HalBtc87232Ant.c */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.c ===== */ + +/* local function start with btdm_ */ +static u8 btdm_ActionAlgorithm(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + u8 bScoExist = false, bBtLinkExist = false, bBtHsModeExist = false; + u8 algorithm = BT_2ANT_COEX_ALGO_UNDEFINED; + + if (pBtMgnt->ExtConfig.NumberOfHandle) + bBtLinkExist = true; + if (pBtMgnt->ExtConfig.NumberOfSCO) + bScoExist = true; + if (BT_HsConnectionEstablished(padapter)) + bBtHsModeExist = true; + + /* here we get BT status first */ + /* 1) initialize */ + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE; + + if ((bScoExist) || (bBtHsModeExist) || + (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID))) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO or HID or HS exists, set BT non-idle !!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE; + } else { + /* A2dp profile */ + if ((pBtMgnt->ExtConfig.NumberOfHandle == 1) && + (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP))) { + if (BTDM_BtTxRxCounterL(padapter) < 100) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP, low priority tx+rx < 100, set BT connected-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP, low priority tx+rx >= 100, set BT non-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE; + } + } + /* Pan profile */ + if ((pBtMgnt->ExtConfig.NumberOfHandle == 1) && + (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN))) { + if (BTDM_BtTxRxCounterL(padapter) < 600) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } else { + if (pHalData->bt_coexist.halCoex8723.lowPriorityTx) { + if ((pHalData->bt_coexist.halCoex8723.lowPriorityRx / + pHalData->bt_coexist.halCoex8723.lowPriorityTx) > 9) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if (BT_2ANT_BT_STATUS_CONNECTED_IDLE != pBtdm8723->btStatus) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, set BT non-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE; + } + } + /* Pan+A2dp profile */ + if ((pBtMgnt->ExtConfig.NumberOfHandle == 2) && + (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) && + (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN))) { + if (BTDM_BtTxRxCounterL(padapter) < 600) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } else { + if (pHalData->bt_coexist.halCoex8723.lowPriorityTx) { + if ((pHalData->bt_coexist.halCoex8723.lowPriorityRx / + pHalData->bt_coexist.halCoex8723.lowPriorityTx) > 9) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if (BT_2ANT_BT_STATUS_CONNECTED_IDLE != pBtdm8723->btStatus) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, set BT non-idle!!!\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE; + } + } + } + if (BT_2ANT_BT_STATUS_IDLE != pBtdm8723->btStatus) + pBtMgnt->ExtConfig.bBTBusy = true; + else + pBtMgnt->ExtConfig.bBTBusy = false; + + if (!bBtLinkExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if (pBtMgnt->ExtConfig.NumberOfHandle == 1) { + if (bScoExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_2ANT_COEX_ALGO_SCO; + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_2ANT_COEX_ALGO_HID; + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_2ANT_COEX_ALGO_A2DP; + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_2ANT_COEX_ALGO_PANHS; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d \n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } + } else if (pBtMgnt->ExtConfig.NumberOfHandle == 2) { + if (bScoExist) { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_2ANT_COEX_ALGO_HID; + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP\n")); + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_SCO; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched ACL profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } + } else if (pBtMgnt->ExtConfig.NumberOfHandle == 3) { + if (bScoExist) { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP\n")); + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_SCO; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP + PAN(EDR)\n")); + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANHS; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } + } else if (pBtMgnt->ExtConfig.NumberOfHandle >= 3) { + if (bScoExist) { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + if (bBtHsModeExist) + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + else + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(EDR)\n")); + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n", + pBtMgnt->ExtConfig.NumberOfHandle)); + } + } + return algorithm; +} + +static u8 btdm_NeedToDecBtPwr(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 bRet = false; + + if (BT_Operation(padapter)) { + if (pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB > 47) { + RTPRINT(FBT, BT_TRACE, ("Need to decrease bt power for HS mode!!\n")); + bRet = true; + } else { + RTPRINT(FBT, BT_TRACE, ("NO Need to decrease bt power for HS mode!!\n")); + } + } else { + if (BTDM_IsWifiConnectionExist(padapter)) { + RTPRINT(FBT, BT_TRACE, ("Need to decrease bt power for Wifi is connected!!\n")); + bRet = true; + } + } + return bRet; +} + +static void +btdm_SetCoexTable(struct rtw_adapter *padapter, u32 val0x6c0, + u32 val0x6c8, u8 val0x6cc) +{ + RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6c0 = 0x%x\n", val0x6c0)); + rtw_write32(padapter, 0x6c0, val0x6c0); + + RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6c8 = 0x%x\n", val0x6c8)); + rtw_write32(padapter, 0x6c8, val0x6c8); + + RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6cc = 0x%x\n", val0x6cc)); + rtw_write8(padapter, 0x6cc, val0x6cc); +} + +static void +btdm_SetSwFullTimeDacSwing(struct rtw_adapter *padapter, u8 bSwDacSwingOn, + u32 swDacSwingLvl) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (bSwDacSwingOn) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SwDacSwing = 0x%x\n", swDacSwingLvl)); + PHY_SetBBReg(padapter, 0x880, 0xff000000, swDacSwingLvl); + pHalData->bt_coexist.bSWCoexistAllOff = false; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SwDacSwing Off!\n")); + PHY_SetBBReg(padapter, 0x880, 0xff000000, 0xc0); + } +} + +static void +btdm_SetFwDacSwingLevel(struct rtw_adapter *padapter, u8 dacSwingLvl) +{ + u8 H2C_Parameter[1] = {0}; + + H2C_Parameter[0] = dacSwingLvl; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Set Dac Swing Level = 0x%x\n", dacSwingLvl)); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], write 0x29 = 0x%x\n", H2C_Parameter[0])); + + FillH2CCmd(padapter, 0x29, 1, H2C_Parameter); +} + +static void btdm_2AntDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], Dec BT power = %s\n", + ((bDecBtPwr) ? "ON" : "OFF"))); + pBtdm8723->bCurDecBtPwr = bDecBtPwr; + + if (pBtdm8723->bPreDecBtPwr == pBtdm8723->bCurDecBtPwr) + return; + + BTDM_SetFwDecBtPwr(padapter, pBtdm8723->bCurDecBtPwr); + + pBtdm8723->bPreDecBtPwr = pBtdm8723->bCurDecBtPwr; +} + +static void +btdm_2AntFwDacSwingLvl(struct rtw_adapter *padapter, u8 fwDacSwingLvl) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], set FW Dac Swing level = %d\n", fwDacSwingLvl)); + pBtdm8723->curFwDacSwingLvl = fwDacSwingLvl; + + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n", */ + /*pBtdm8723->preFwDacSwingLvl, pBtdm8723->curFwDacSwingLvl)); */ + + if (pBtdm8723->preFwDacSwingLvl == pBtdm8723->curFwDacSwingLvl) + return; + + btdm_SetFwDacSwingLevel(padapter, pBtdm8723->curFwDacSwingLvl); + + pBtdm8723->preFwDacSwingLvl = pBtdm8723->curFwDacSwingLvl; +} + +static void +btdm_2AntRfShrink(struct rtw_adapter *padapter, u8 bRxRfShrinkOn) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn Rx RF Shrink = %s\n", + ((bRxRfShrinkOn) ? "ON" : "OFF"))); + pBtdm8723->bCurRfRxLpfShrink = bRxRfShrinkOn; + + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n", */ + /*pBtdm8723->bPreRfRxLpfShrink, pBtdm8723->bCurRfRxLpfShrink)); */ + + if (pBtdm8723->bPreRfRxLpfShrink == pBtdm8723->bCurRfRxLpfShrink) + return; + + BTDM_SetSwRfRxLpfCorner(padapter, (u8)pBtdm8723->bCurRfRxLpfShrink); + + pBtdm8723->bPreRfRxLpfShrink = pBtdm8723->bCurRfRxLpfShrink; +} + +static void +btdm_2AntLowPenaltyRa(struct rtw_adapter *padapter, u8 bLowPenaltyRa) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn LowPenaltyRA = %s\n", + ((bLowPenaltyRa) ? "ON" : "OFF"))); + pBtdm8723->bCurLowPenaltyRa = bLowPenaltyRa; + + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreLowPenaltyRa =%d, bCurLowPenaltyRa =%d\n", */ + /*pBtdm8723->bPreLowPenaltyRa, pBtdm8723->bCurLowPenaltyRa)); */ + + if (pBtdm8723->bPreLowPenaltyRa == pBtdm8723->bCurLowPenaltyRa) + return; + + BTDM_SetSwPenaltyTxRateAdaptive(padapter, (u8)pBtdm8723->bCurLowPenaltyRa); + + pBtdm8723->bPreLowPenaltyRa = pBtdm8723->bCurLowPenaltyRa; +} + +static void +btdm_2AntDacSwing(struct rtw_adapter *padapter, + u8 bDacSwingOn, u32 dacSwingLvl) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn DacSwing =%s, dacSwingLvl = 0x%x\n", + (bDacSwingOn ? "ON" : "OFF"), dacSwingLvl)); + pBtdm8723->bCurDacSwingOn = bDacSwingOn; + pBtdm8723->curDacSwingLvl = dacSwingLvl; + + if ((pBtdm8723->bPreDacSwingOn == pBtdm8723->bCurDacSwingOn) && + (pBtdm8723->preDacSwingLvl == pBtdm8723->curDacSwingLvl)) + return; + + mdelay(30); + btdm_SetSwFullTimeDacSwing(padapter, bDacSwingOn, dacSwingLvl); + + pBtdm8723->bPreDacSwingOn = pBtdm8723->bCurDacSwingOn; + pBtdm8723->preDacSwingLvl = pBtdm8723->curDacSwingLvl; +} + +static void btdm_2AntAdcBackOff(struct rtw_adapter *padapter, u8 bAdcBackOff) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn AdcBackOff = %s\n", + ((bAdcBackOff) ? "ON" : "OFF"))); + pBtdm8723->bCurAdcBackOff = bAdcBackOff; + + if (pBtdm8723->bPreAdcBackOff == pBtdm8723->bCurAdcBackOff) + return; + + BTDM_BBBackOffLevel(padapter, (u8)pBtdm8723->bCurAdcBackOff); + + pBtdm8723->bPreAdcBackOff = pBtdm8723->bCurAdcBackOff; +} + +static void btdm_2AntAgcTable(struct rtw_adapter *padapter, u8 bAgcTableEn) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], %s Agc Table\n", ((bAgcTableEn) ? "Enable" : "Disable"))); + pBtdm8723->bCurAgcTableEn = bAgcTableEn; + + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n", */ + /*pBtdm8723->bPreAgcTableEn, pBtdm8723->bCurAgcTableEn)); */ + + if (pBtdm8723->bPreAgcTableEn == pBtdm8723->bCurAgcTableEn) + return; + + BTDM_AGCTable(padapter, (u8)bAgcTableEn); + + pBtdm8723->bPreAgcTableEn = pBtdm8723->bCurAgcTableEn; +} + +static void +btdm_2AntCoexTable(struct rtw_adapter *padapter, + u32 val0x6c0, u32 val0x6c8, u8 val0x6cc) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], write Coex Table 0x6c0 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", + val0x6c0, val0x6c8, val0x6cc)); + pBtdm8723->curVal0x6c0 = val0x6c0; + pBtdm8723->curVal0x6c8 = val0x6c8; + pBtdm8723->curVal0x6cc = val0x6cc; + + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n", */ + /*pBtdm8723->preVal0x6c0, pBtdm8723->preVal0x6c8, pBtdm8723->preVal0x6cc)); */ + /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", */ + /*pBtdm8723->curVal0x6c0, pBtdm8723->curVal0x6c8, pBtdm8723->curVal0x6cc)); */ + + if ((pBtdm8723->preVal0x6c0 == pBtdm8723->curVal0x6c0) && + (pBtdm8723->preVal0x6c8 == pBtdm8723->curVal0x6c8) && + (pBtdm8723->preVal0x6cc == pBtdm8723->curVal0x6cc)) + return; + + btdm_SetCoexTable(padapter, val0x6c0, val0x6c8, val0x6cc); + + pBtdm8723->preVal0x6c0 = pBtdm8723->curVal0x6c0; + pBtdm8723->preVal0x6c8 = pBtdm8723->curVal0x6c8; + pBtdm8723->preVal0x6cc = pBtdm8723->curVal0x6cc; +} + +static void btdm_2AntIgnoreWlanAct(struct rtw_adapter *padapter, u8 bEnable) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn Ignore WlanAct %s\n", (bEnable ? "ON" : "OFF"))); + pBtdm8723->bCurIgnoreWlanAct = bEnable; + + + if (pBtdm8723->bPreIgnoreWlanAct == pBtdm8723->bCurIgnoreWlanAct) + return; + + btdm_SetFwIgnoreWlanAct(padapter, bEnable); + pBtdm8723->bPreIgnoreWlanAct = pBtdm8723->bCurIgnoreWlanAct; +} + +static void +btdm_2AntSetFw3a(struct rtw_adapter *padapter, u8 byte1, u8 byte2, + u8 byte3, u8 byte4, u8 byte5) +{ + u8 H2C_Parameter[5] = {0}; + + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* byte1[1:0] != 0 means enable pstdma */ + /* for 2Ant bt coexist, if byte1 != 0 means enable pstdma */ + if (byte1) + pHalData->bt_coexist.bFWCoexistAllOff = false; + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pHalData->bt_coexist.fw3aVal[0] = byte1; + pHalData->bt_coexist.fw3aVal[1] = byte2; + pHalData->bt_coexist.fw3aVal[2] = byte3; + pHalData->bt_coexist.fw3aVal[3] = byte4; + pHalData->bt_coexist.fw3aVal[4] = byte5; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], FW write 0x3a(5bytes) = 0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + FillH2CCmd(padapter, 0x3a, 5, H2C_Parameter); + } + +static void btdm_2AntPsTdma(struct rtw_adapter *padapter, u8 bTurnOn, u8 type) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + u32 btTxRxCnt = 0; + u8 bTurnOnByCnt = false; + u8 psTdmaTypeByCnt = 0; + + btTxRxCnt = BTDM_BtTxRxCounterH(padapter)+BTDM_BtTxRxCounterL(padapter); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT TxRx Counters = %d\n", btTxRxCnt)); + if (btTxRxCnt > 3000) { + bTurnOnByCnt = true; + psTdmaTypeByCnt = 8; + + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], For BTTxRxCounters, turn %s PS TDMA, type =%d\n", + (bTurnOnByCnt ? "ON" : "OFF"), psTdmaTypeByCnt)); + pBtdm8723->bCurPsTdmaOn = bTurnOnByCnt; + pBtdm8723->curPsTdma = psTdmaTypeByCnt; + } else { + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], turn %s PS TDMA, type =%d\n", + (bTurnOn ? "ON" : "OFF"), type)); + pBtdm8723->bCurPsTdmaOn = bTurnOn; + pBtdm8723->curPsTdma = type; + } + + if ((pBtdm8723->bPrePsTdmaOn == pBtdm8723->bCurPsTdmaOn) && + (pBtdm8723->prePsTdma == pBtdm8723->curPsTdma)) + return; + + if (bTurnOn) { + switch (type) { + case 1: + default: + btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0xa1, 0x98); + break; + case 2: + btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0xa1, 0x98); + break; + case 3: + btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0xa1, 0x98); + break; + case 4: + btdm_2AntSetFw3a(padapter, 0xa3, 0x5, 0x5, 0xa1, 0x80); + break; + case 5: + btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x20, 0x98); + break; + case 6: + btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0x20, 0x98); + break; + case 7: + btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0x20, 0x98); + break; + case 8: + btdm_2AntSetFw3a(padapter, 0xa3, 0x5, 0x5, 0x20, 0x80); + break; + case 9: + btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0xa1, 0x98); + break; + case 10: + btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0xa1, 0x98); + break; + case 11: + btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0xa1, 0x98); + break; + case 12: + btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0xa1, 0x98); + break; + case 13: + btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x20, 0x98); + break; + case 14: + btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0x20, 0x98); + break; + case 15: + btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0x20, 0x98); + break; + case 16: + btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0x20, 0x98); + break; + case 17: + btdm_2AntSetFw3a(padapter, 0xa3, 0x2f, 0x2f, 0x20, 0x80); + break; + case 18: + btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0xa1, 0x98); + break; + case 19: + btdm_2AntSetFw3a(padapter, 0xe3, 0x25, 0x25, 0xa1, 0x98); + break; + case 20: + btdm_2AntSetFw3a(padapter, 0xe3, 0x25, 0x25, 0x20, 0x98); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + case 1: + btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x0, 0x0); + break; + default: + btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + } + } + + /* update pre state */ + pBtdm8723->bPrePsTdmaOn = pBtdm8723->bCurPsTdmaOn; + pBtdm8723->prePsTdma = pBtdm8723->curPsTdma; +} + +static void btdm_2AntBtInquiryPage(struct rtw_adapter *padapter) +{ + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, true, 8); +} + +static u8 btdm_HoldForBtInqPage(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 curTime = rtw_get_current_time(); + + if (pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage) { + /* bt inquiry or page is started. */ + if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime == 0) { + pHalData->bt_coexist.halCoex8723.btInqPageStartTime = curTime; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page is started at time : 0x%"i64fmt"x \n", + pHalData->bt_coexist.halCoex8723.btInqPageStartTime)); + } + } + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page started time : 0x%"i64fmt"x, curTime : 0x%x \n", + pHalData->bt_coexist.halCoex8723.btInqPageStartTime, curTime)); + + if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime) { + if (((curTime - pHalData->bt_coexist.halCoex8723.btInqPageStartTime)/1000000) >= 10) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page >= 10sec!!!")); + pHalData->bt_coexist.halCoex8723.btInqPageStartTime = 0; + } + } + + if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime) { + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, true, 8); + return true; + } else { + return false; + } +} + +static u8 btdm_Is2Ant8723ACommonAction(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + u8 bCommon = false; + + RTPRINT(FBT, BT_TRACE, ("%s :BTDM_IsWifiConnectionExist =%x check_fwstate =%x pmlmepriv->fw_state = 0x%x\n", __func__, BTDM_IsWifiConnectionExist(padapter), check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)), padapter->mlmepriv.fw_state)); + + if ((!BTDM_IsWifiConnectionExist(padapter)) && + (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) && + (BT_2ANT_BT_STATUS_IDLE == pBtdm8723->btStatus)) { + RTPRINT(FBT, BT_TRACE, ("Wifi idle + Bt idle!!\n")); + + btdm_2AntLowPenaltyRa(padapter, false); + btdm_2AntRfShrink(padapter, false); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, false); + + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + + bCommon = true; + } else if (((BTDM_IsWifiConnectionExist(padapter)) || + (check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) && + (BT_2ANT_BT_STATUS_IDLE == pBtdm8723->btStatus)) { + RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + BT idle!!\n")); + + btdm_2AntLowPenaltyRa(padapter, true); + btdm_2AntRfShrink(padapter, false); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, true); + + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + + bCommon = true; + } else if ((!BTDM_IsWifiConnectionExist(padapter)) && + (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) && + (BT_2ANT_BT_STATUS_CONNECTED_IDLE == pBtdm8723->btStatus)) { + RTPRINT(FBT, BT_TRACE, ("Wifi idle + Bt connected idle!!\n")); + + btdm_2AntLowPenaltyRa(padapter, true); + btdm_2AntRfShrink(padapter, true); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, false); + + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + + bCommon = true; + } else if (((BTDM_IsWifiConnectionExist(padapter)) || + (check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) && + (BT_2ANT_BT_STATUS_CONNECTED_IDLE == pBtdm8723->btStatus)) { + RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + Bt connected idle!!\n")); + + btdm_2AntLowPenaltyRa(padapter, true); + btdm_2AntRfShrink(padapter, true); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, true); + + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + + bCommon = true; + } else if ((!BTDM_IsWifiConnectionExist(padapter)) && + (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) && + (BT_2ANT_BT_STATUS_NON_IDLE == pBtdm8723->btStatus)) { + RTPRINT(FBT, BT_TRACE, ("Wifi idle + BT non-idle!!\n")); + + btdm_2AntLowPenaltyRa(padapter, true); + btdm_2AntRfShrink(padapter, true); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, false); + + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + + bCommon = true; + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + BT non-idle!!\n")); + btdm_2AntLowPenaltyRa(padapter, true); + btdm_2AntRfShrink(padapter, true); + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + + bCommon = false; + } + return bCommon; +} + +static void +btdm_2AntTdmaDurationAdjust(struct rtw_adapter *padapter, u8 bScoHid, + u8 bTxPause, u8 maxInterval) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + static s32 up, dn, m, n, WaitCount; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retryCount = 0; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TdmaDurationAdjust()\n")); + + if (pBtdm8723->bResetTdmaAdjust) { + pBtdm8723->bResetTdmaAdjust = false; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + if (bScoHid) { + if (bTxPause) { + if (maxInterval == 1) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (maxInterval == 2) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (maxInterval == 3) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } + } else { + if (maxInterval == 1) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (maxInterval == 2) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (maxInterval == 3) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } + } + } else { + if (bTxPause) { + if (maxInterval == 1) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (maxInterval == 2) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (maxInterval == 3) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } + } else { + if (maxInterval == 1) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (maxInterval == 2) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (maxInterval == 3) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } + } + } + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + WaitCount = 0; + } else { + /* accquire the BT TRx retry count from BT_Info byte2 */ + retryCount = pHalData->bt_coexist.halCoex8723.btRetryCnt; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], retryCount = %d\n", retryCount)); + result = 0; + WaitCount++; + + if (retryCount == 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration */ + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Increase wifi duration!!\n")); + } + } else if (retryCount <= 3) { /* <= 3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration */ + if (WaitCount <= 2) + m++; /* ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ */ + else + m = 1; + + if (m >= 20) /* m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. */ + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } else { /* retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration */ + if (WaitCount == 1) + m++; /* ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ */ + else + m = 1; + + if (m >= 20) /* m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. */ + m = 20; + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], max Interval = %d\n", maxInterval)); + if (maxInterval == 1) { + if (bTxPause) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n")); + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 5); + pBtdm8723->psTdmaDuAdjType = 5; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } + if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 13); + pBtdm8723->psTdmaDuAdjType = 13; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + + if (result == -1) { + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } else if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 5); + pBtdm8723->psTdmaDuAdjType = 5; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 13); + pBtdm8723->psTdmaDuAdjType = 13; + } + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n")); + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 1); + pBtdm8723->psTdmaDuAdjType = 1; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } + if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 9); + pBtdm8723->psTdmaDuAdjType = 9; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + + if (result == -1) { + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } else if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 1); + pBtdm8723->psTdmaDuAdjType = 1; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 9); + pBtdm8723->psTdmaDuAdjType = 9; + } + } + } + } else if (maxInterval == 2) { + if (bTxPause) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n")); + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } + if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + if (result == -1) { + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } else if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 6); + pBtdm8723->psTdmaDuAdjType = 6; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 14); + pBtdm8723->psTdmaDuAdjType = 14; + } + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n")); + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } + if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + if (result == -1) { + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } else if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 2); + pBtdm8723->psTdmaDuAdjType = 2; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 10); + pBtdm8723->psTdmaDuAdjType = 10; + } + } + } + } else if (maxInterval == 3) { + if (bTxPause) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n")); + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } + if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + if (result == -1) { + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 8); + pBtdm8723->psTdmaDuAdjType = 8; + } else if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 16); + pBtdm8723->psTdmaDuAdjType = 16; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 7); + pBtdm8723->psTdmaDuAdjType = 7; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 15); + pBtdm8723->psTdmaDuAdjType = 15; + } + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n")); + if (pBtdm8723->curPsTdma == 5) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 6) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 7) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 8) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } + if (pBtdm8723->curPsTdma == 13) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 14) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 15) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 16) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + if (result == -1) { + if (pBtdm8723->curPsTdma == 1) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 4); + pBtdm8723->psTdmaDuAdjType = 4; + } else if (pBtdm8723->curPsTdma == 9) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 12); + pBtdm8723->psTdmaDuAdjType = 12; + } + } else if (result == 1) { + if (pBtdm8723->curPsTdma == 4) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 3) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 2) { + btdm_2AntPsTdma(padapter, true, 3); + pBtdm8723->psTdmaDuAdjType = 3; + } else if (pBtdm8723->curPsTdma == 12) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 11) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } else if (pBtdm8723->curPsTdma == 10) { + btdm_2AntPsTdma(padapter, true, 11); + pBtdm8723->psTdmaDuAdjType = 11; + } + } + } + } + } + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PsTdma type : recordPsTdma =%d\n", pBtdm8723->psTdmaDuAdjType)); + /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if (pBtdm8723->curPsTdma != pBtdm8723->psTdmaDuAdjType) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma =%d, recordPsTdma =%d\n", + pBtdm8723->curPsTdma, pBtdm8723->psTdmaDuAdjType)); + + if (!check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) + btdm_2AntPsTdma(padapter, true, pBtdm8723->psTdmaDuAdjType); + else + RTPRINT(FBT, BT_TRACE, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } +} + +/* default Action */ +/* SCO only or SCO+PAN(HS) */ +static void btdm_2Ant8723ASCOAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 11); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 15); + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 11); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 15); + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +static void btdm_2Ant8723AHIDAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 9); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 13); + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 9); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 13); + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void btdm_2Ant8723AA2DPAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 1); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 1); + } + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 1); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 1); + } + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +static void btdm_2Ant8723APANEDRAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 2); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntPsTdma(padapter, true, 6); + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 2); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 6); + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +/* PAN(HS) only */ +static void btdm_2Ant8723APANHSAction(struct rtw_adapter *padapter) +{ + u8 btRssiState; + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0); + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntDecBtPwr(padapter, true); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntDecBtPwr(padapter, false); + } + btdm_2AntPsTdma(padapter, false, 0); + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0); + + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high\n")); + /* fw mechanism */ + btdm_2AntDecBtPwr(padapter, true); + btdm_2AntPsTdma(padapter, false, 0); + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low\n")); + /* fw mechanism */ + btdm_2AntDecBtPwr(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +/* PAN(EDR)+A2DP */ +static void btdm_2Ant8723APANEDRA2DPAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1, btInfoExt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + /* fw mechanism */ + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 4); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 2); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + /* fw mechanism */ + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 8); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 6); + } + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + /* fw mechanism */ + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 4); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 2); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + /* fw mechanism */ + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 8); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 6); + } + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +static void btdm_2Ant8723APANEDRHIDAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 10); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntPsTdma(padapter, true, 14); + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntPsTdma(padapter, true, 10); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntPsTdma(padapter, true, 14); + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +static void btdm_2Ant8723AHIDA2DPPANEDRAction(struct rtw_adapter *padapter) +{ + u8 btRssiState, btRssiState1, btInfoExt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 12); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 10); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 16); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 14); + } + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 37, 0); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 27, 0); + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 12); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 10); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntPsTdma(padapter, true, 16); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntPsTdma(padapter, true, 14); + } + } + + /* sw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +static void btdm_2Ant8723AHIDA2DPAction(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 btRssiState, btRssiState1, btInfoExt; + + btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, false, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, false, 1); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, true, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, true, 1); + } + } + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + btRssiState1 = BTDM_CheckCoexRSSIState(padapter, 2, 27, 0); + + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, false, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, false, 1); + } + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */ + RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, true, 3); + } else { + RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n")); + btdm_2AntTdmaDurationAdjust(padapter, true, true, 1); + } + } + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + /* sw mechanism */ + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +static void btdm_2Ant8723AA2dp(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 btRssiState, btRssiState1, btInfoExt; + + btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + + if (btdm_NeedToDecBtPwr(padapter)) + btdm_2AntDecBtPwr(padapter, true); + else + btdm_2AntDecBtPwr(padapter, false); + /* coex table */ + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + btdm_2AntIgnoreWlanAct(padapter, false); + + if (BTDM_IsHT40(padapter)) { + RTPRINT(FBT, BT_TRACE, ("HT40\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0); + /* fw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 1); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 1); + } + + /* sw mechanism */ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n")); + btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0); + btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0); + + /* fw mechanism */ + if ((btRssiState1 == BT_RSSI_STATE_HIGH) || + (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n")); + PlatformEFIOWrite1Byte(padapter, 0x883, 0x40); + btdm_2AntTdmaDurationAdjust(padapter, false, false, 1); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n")); + btdm_2AntTdmaDurationAdjust(padapter, false, true, 1); + } + + /* sw mechanism */ + if ((btRssiState == BT_RSSI_STATE_HIGH) || + (btRssiState == BT_RSSI_STATE_STAY_HIGH)) { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n")); + btdm_2AntAgcTable(padapter, true); + btdm_2AntAdcBackOff(padapter, true); + btdm_2AntDacSwing(padapter, false, 0xc0); + } else { + RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n")); + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); + } + } +} + +/* extern function start with BTDM_ */ +static void BTDM_2AntParaInit(struct rtw_adapter *padapter) +{ + + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 2Ant Parameter Init!!\n")); + + /* Enable counter statistics */ + rtw_write8(padapter, 0x76e, 0x4); + rtw_write8(padapter, 0x778, 0x3); + rtw_write8(padapter, 0x40, 0x20); + + /* force to reset coex mechanism */ + pBtdm8723->preVal0x6c0 = 0x0; + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); + + pBtdm8723->bPrePsTdmaOn = true; + btdm_2AntPsTdma(padapter, false, 0); + + pBtdm8723->preFwDacSwingLvl = 0x10; + btdm_2AntFwDacSwingLvl(padapter, 0x20); + + pBtdm8723->bPreDecBtPwr = true; + btdm_2AntDecBtPwr(padapter, false); + + pBtdm8723->bPreAgcTableEn = true; + btdm_2AntAgcTable(padapter, false); + + pBtdm8723->bPreAdcBackOff = true; + btdm_2AntAdcBackOff(padapter, false); + + pBtdm8723->bPreLowPenaltyRa = true; + btdm_2AntLowPenaltyRa(padapter, false); + + pBtdm8723->bPreRfRxLpfShrink = true; + btdm_2AntRfShrink(padapter, false); + + pBtdm8723->bPreDacSwingOn = true; + btdm_2AntDacSwing(padapter, false, 0xc0); + + pBtdm8723->bPreIgnoreWlanAct = true; + btdm_2AntIgnoreWlanAct(padapter, false); +} + +static void BTDM_2AntHwCoexAllOff8723A(struct rtw_adapter *padapter) +{ + btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3); +} + +static void BTDM_2AntFwCoexAllOff8723A(struct rtw_adapter *padapter) +{ + btdm_2AntIgnoreWlanAct(padapter, false); + btdm_2AntPsTdma(padapter, false, 0); + btdm_2AntFwDacSwingLvl(padapter, 0x20); + btdm_2AntDecBtPwr(padapter, false); +} + +static void BTDM_2AntSwCoexAllOff8723A(struct rtw_adapter *padapter) +{ + btdm_2AntAgcTable(padapter, false); + btdm_2AntAdcBackOff(padapter, false); + btdm_2AntLowPenaltyRa(padapter, false); + btdm_2AntRfShrink(padapter, false); + btdm_2AntDacSwing(padapter, false, 0xc0); +} + +static void BTDM_2AntFwC2hBtInfo8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + u8 btInfo = 0; + u8 algorithm = BT_2ANT_COEX_ALGO_UNDEFINED; + u8 bBtLinkExist = false, bBtHsModeExist = false; + + btInfo = pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal; + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE; + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (btInfo & BIT(2)) { + if (!pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage) { + pBtMgnt->ExtConfig.bHoldForBtOperation = true; + pBtMgnt->ExtConfig.bHoldPeriodCnt = 1; + btdm_2AntBtInquiryPage(padapter); + } else { + pBtMgnt->ExtConfig.bHoldPeriodCnt++; + btdm_HoldForBtInqPage(padapter); + } + pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage = true; + + } else { + pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage = false; + pBtMgnt->ExtConfig.bHoldForBtOperation = false; + pBtMgnt->ExtConfig.bHoldPeriodCnt = 0; + + } + RTPRINT(FBT, BT_TRACE, + ("[BTC2H], pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage =%x pBtMgnt->ExtConfig.bHoldPeriodCnt =%x pBtMgnt->ExtConfig.bHoldForBtOperation =%x\n", + pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage, + pBtMgnt->ExtConfig.bHoldPeriodCnt, + pBtMgnt->ExtConfig.bHoldForBtOperation)); + + RTPRINT(FBT, BT_TRACE, + ("[BTC2H], btInfo =%x pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal =%x\n", + btInfo, pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal)); + if (btInfo&BT_INFO_ACL) { + RTPRINT(FBT, BT_TRACE, ("[BTC2H], BTInfo: bConnect = true btInfo =%x\n", btInfo)); + bBtLinkExist = true; + if (((btInfo&(BT_INFO_FTP|BT_INFO_A2DP|BT_INFO_HID|BT_INFO_SCO_BUSY)) != 0) || + pHalData->bt_coexist.halCoex8723.btRetryCnt > 0) { + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE; + } else { + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE; + } + + if (btInfo&BT_INFO_SCO || btInfo&BT_INFO_SCO_BUSY) { + if (btInfo&BT_INFO_FTP || btInfo&BT_INFO_A2DP || btInfo&BT_INFO_HID) { + switch (btInfo&0xe0) { + case BT_INFO_HID: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_2ANT_COEX_ALGO_HID; + break; + case BT_INFO_A2DP: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP\n")); + break; + case BT_INFO_FTP: + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_SCO; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + break; + case (BT_INFO_HID | BT_INFO_A2DP): + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + break; + case (BT_INFO_HID | BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + break; + case (BT_INFO_A2DP | BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP; + } + break; + case (BT_INFO_HID | BT_INFO_A2DP | BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + break; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_2ANT_COEX_ALGO_SCO; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], non SCO\n")); + switch (btInfo&0xe0) { + case BT_INFO_HID: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID\n")); + algorithm = BT_2ANT_COEX_ALGO_HID; + break; + case BT_INFO_A2DP: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP\n")); + algorithm = BT_2ANT_COEX_ALGO_A2DP; + break; + case BT_INFO_FTP: + RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + break; + case (BT_INFO_HID | BT_INFO_A2DP): + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + break; + case (BT_INFO_HID|BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID; + } + break; + case (BT_INFO_A2DP|BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP; + } + break; + case (BT_INFO_HID|BT_INFO_A2DP|BT_INFO_FTP): + if (bBtHsModeExist) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP; + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + break; + } + + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTC2H], BTInfo: bConnect = false\n")); + pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE; + } + + pBtdm8723->curAlgorithm = algorithm; + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Algorithm = %d \n", pBtdm8723->curAlgorithm)); + +/* From */ + BTDM_CheckWiFiState(padapter); + if (pBtMgnt->ExtConfig.bManualControl) { + RTPRINT(FBT, BT_TRACE, ("Action Manual control, won't execute bt coexist mechanism!!\n")); + return; + } +} + +void BTDM_2AntBtCoexist8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct bt_dgb *pBtDbg = &pBTInfo->BtDbg; + u8 btInfoOriginal = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant; + + if (BTDM_BtProfileSupport(padapter)) { + if (pBtMgnt->ExtConfig.bHoldForBtOperation) { + RTPRINT(FBT, BT_TRACE, ("Action for BT Operation adjust!!\n")); + return; + } + if (pBtMgnt->ExtConfig.bHoldPeriodCnt) { + RTPRINT(FBT, BT_TRACE, ("Hold BT inquiry/page scan setting (cnt = %d)!!\n", + pBtMgnt->ExtConfig.bHoldPeriodCnt)); + if (pBtMgnt->ExtConfig.bHoldPeriodCnt >= 11) { + pBtMgnt->ExtConfig.bHoldPeriodCnt = 0; + /* next time the coexist parameters should be reset again. */ + } else { + pBtMgnt->ExtConfig.bHoldPeriodCnt++; + } + return; + } + + if (pBtDbg->dbgCtrl) + RTPRINT(FBT, BT_TRACE, ("[Dbg control], ")); + + pBtdm8723->curAlgorithm = btdm_ActionAlgorithm(padapter); + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Algorithm = %d \n", pBtdm8723->curAlgorithm)); + + if (btdm_Is2Ant8723ACommonAction(padapter)) { + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant common.\n")); + pBtdm8723->bResetTdmaAdjust = true; + } else { + if (pBtdm8723->curAlgorithm != pBtdm8723->preAlgorithm) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n", + pBtdm8723->preAlgorithm, pBtdm8723->curAlgorithm)); + pBtdm8723->bResetTdmaAdjust = true; + } + switch (pBtdm8723->curAlgorithm) { + case BT_2ANT_COEX_ALGO_SCO: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = SCO.\n")); + btdm_2Ant8723ASCOAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID.\n")); + btdm_2Ant8723AHIDAction(padapter); + break; + case BT_2ANT_COEX_ALGO_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = A2DP.\n")); + btdm_2Ant8723AA2DPAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR).\n")); + btdm_2Ant8723APANEDRAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANHS: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HS mode.\n")); + btdm_2Ant8723APANHSAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN+A2DP.\n")); + btdm_2Ant8723APANEDRA2DPAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR_HID: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + btdm_2Ant8723APANEDRHIDAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + btdm_2Ant8723AHIDA2DPPANEDRAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP.\n")); + btdm_2Ant8723AHIDA2DPAction(padapter); + break; + default: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = 0.\n")); + btdm_2Ant8723AA2DPAction(padapter); + break; + } + pBtdm8723->preAlgorithm = pBtdm8723->curAlgorithm; + } + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex] Get bt info by fw!!\n")); + /* msg shows c2h rsp for bt_info is received or not. */ + if (pHalData->bt_coexist.halCoex8723.bC2hBtInfoReqSent) + RTPRINT(FBT, BT_TRACE, ("[BTCoex] c2h for btInfo not rcvd yet!!\n")); + + btInfoOriginal = pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal; + + if (pBtMgnt->ExtConfig.bHoldForBtOperation) { + RTPRINT(FBT, BT_TRACE, ("Action for BT Operation adjust!!\n")); + return; + } + if (pBtMgnt->ExtConfig.bHoldPeriodCnt) { + RTPRINT(FBT, BT_TRACE, + ("Hold BT inquiry/page scan setting (cnt = %d)!!\n", + pBtMgnt->ExtConfig.bHoldPeriodCnt)); + if (pBtMgnt->ExtConfig.bHoldPeriodCnt >= 11) { + pBtMgnt->ExtConfig.bHoldPeriodCnt = 0; + /* next time the coexist parameters should be reset again. */ + } else { + pBtMgnt->ExtConfig.bHoldPeriodCnt++; + } + return; + } + + if (pBtDbg->dbgCtrl) + RTPRINT(FBT, BT_TRACE, ("[Dbg control], ")); + if (btdm_Is2Ant8723ACommonAction(padapter)) { + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant common.\n")); + pBtdm8723->bResetTdmaAdjust = true; + } else { + if (pBtdm8723->curAlgorithm != pBtdm8723->preAlgorithm) { + RTPRINT(FBT, BT_TRACE, + ("[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n", + pBtdm8723->preAlgorithm, + pBtdm8723->curAlgorithm)); + pBtdm8723->bResetTdmaAdjust = true; + } + switch (pBtdm8723->curAlgorithm) { + case BT_2ANT_COEX_ALGO_SCO: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = SCO.\n")); + btdm_2Ant8723ASCOAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID.\n")); + btdm_2Ant8723AHIDAction(padapter); + break; + case BT_2ANT_COEX_ALGO_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = A2DP.\n")); + btdm_2Ant8723AA2dp(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR).\n")); + btdm_2Ant8723APANEDRAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANHS: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HS mode.\n")); + btdm_2Ant8723APANHSAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN+A2DP.\n")); + btdm_2Ant8723APANEDRA2DPAction(padapter); + break; + case BT_2ANT_COEX_ALGO_PANEDR_HID: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + btdm_2Ant8723APANEDRHIDAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + btdm_2Ant8723AHIDA2DPPANEDRAction(padapter); + break; + case BT_2ANT_COEX_ALGO_HID_A2DP: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP.\n")); + btdm_2Ant8723AHIDA2DPAction(padapter); + break; + default: + RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = 0.\n")); + btdm_2Ant8723AA2DPAction(padapter); + break; + } + pBtdm8723->preAlgorithm = pBtdm8723->curAlgorithm; + } + } +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.c ===== */ +#endif + +#ifdef __HALBTC8723_C__ /* HAL/BTCoexist/HalBtc8723.c */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.c ===== */ + +static u8 btCoexDbgBuf[BT_TMP_BUF_SIZE]; + +static const char *const BtProfileString[] = { + "NONE", + "A2DP", + "PAN", + "HID", + "SCO", +}; + +static const char *const BtSpecString[] = { + "1.0b", + "1.1", + "1.2", + "2.0+EDR", + "2.1+EDR", + "3.0+HS", + "4.0", +}; + +static const char *const BtLinkRoleString[] = { + "Master", + "Slave", +}; + +static u8 btdm_BtWifiAntNum(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723; + + if (Ant_x2 == pHalData->bt_coexist.BT_Ant_Num) { + if (Ant_x2 == pBtCoex->TotalAntNum) + return Ant_x2; + else + return Ant_x1; + } else { + return Ant_x1; + } + return Ant_x2; +} + +static void btdm_BtHwCountersMonitor(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 regHPTxRx, regLPTxRx, u4Tmp; + u32 regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0; + + regHPTxRx = REG_HIGH_PRIORITY_TXRX; + regLPTxRx = REG_LOW_PRIORITY_TXRX; + + u4Tmp = rtw_read32(padapter, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = rtw_read32(padapter, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pHalData->bt_coexist.halCoex8723.highPriorityTx = regHPTx; + pHalData->bt_coexist.halCoex8723.highPriorityRx = regHPRx; + pHalData->bt_coexist.halCoex8723.lowPriorityTx = regLPTx; + pHalData->bt_coexist.halCoex8723.lowPriorityRx = regLPRx; + + RTPRINT(FBT, BT_TRACE, ("High Priority Tx/Rx = %d / %d\n", regHPTx, regHPRx)); + RTPRINT(FBT, BT_TRACE, ("Low Priority Tx/Rx = %d / %d\n", regLPTx, regLPRx)); + + /* reset counter */ + rtw_write8(padapter, 0x76e, 0xc); +} + +/* This function check if 8723 bt is disabled */ +static void btdm_BtEnableDisableCheck8723A(struct rtw_adapter *padapter) +{ + u8 btAlife = true; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + +#ifdef CHECK_BT_EXIST_FROM_REG + u8 val8; + + /* ox68[28]= 1 => BT enable; otherwise disable */ + val8 = rtw_read8(padapter, 0x6B); + if (!(val8 & BIT(4))) + btAlife = false; + + if (btAlife) + pHalData->bt_coexist.bCurBtDisabled = false; + else + pHalData->bt_coexist.bCurBtDisabled = true; +#else + if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0 && + pHalData->bt_coexist.halCoex8723.highPriorityRx == 0 && + pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0 && + pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0) + btAlife = false; + if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0xeaea && + pHalData->bt_coexist.halCoex8723.highPriorityRx == 0xeaea && + pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0xeaea && + pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0xeaea) + btAlife = false; + if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0xffff && + pHalData->bt_coexist.halCoex8723.highPriorityRx == 0xffff && + pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0xffff && + pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0xffff) + btAlife = false; + if (btAlife) { + pHalData->bt_coexist.btActiveZeroCnt = 0; + pHalData->bt_coexist.bCurBtDisabled = false; + RTPRINT(FBT, BT_TRACE, ("8723A BT is enabled !!\n")); + } else { + pHalData->bt_coexist.btActiveZeroCnt++; + RTPRINT(FBT, BT_TRACE, ("8723A bt all counters = 0, %d times!!\n", + pHalData->bt_coexist.btActiveZeroCnt)); + if (pHalData->bt_coexist.btActiveZeroCnt >= 2) { + pHalData->bt_coexist.bCurBtDisabled = true; + RTPRINT(FBT, BT_TRACE, ("8723A BT is disabled !!\n")); + } + } +#endif + + if (!pHalData->bt_coexist.bCurBtDisabled) { + if (BTDM_IsWifiConnectionExist(padapter)) + BTDM_SetFwChnlInfo(padapter, RT_MEDIA_CONNECT); + else + BTDM_SetFwChnlInfo(padapter, RT_MEDIA_DISCONNECT); + } + + if (pHalData->bt_coexist.bPreBtDisabled != + pHalData->bt_coexist.bCurBtDisabled) { + RTPRINT(FBT, BT_TRACE, ("8723A BT is from %s to %s!!\n", + (pHalData->bt_coexist.bPreBtDisabled ? "disabled":"enabled"), + (pHalData->bt_coexist.bCurBtDisabled ? "disabled":"enabled"))); + pHalData->bt_coexist.bPreBtDisabled = pHalData->bt_coexist.bCurBtDisabled; + } +} + +static void btdm_BTCoexist8723AHandler(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + + pHalData = GET_HAL_DATA(padapter); + + if (btdm_BtWifiAntNum(padapter) == Ant_x2) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 2 Ant mechanism\n")); + BTDM_2AntBtCoexist8723A(padapter); + } else { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1 Ant mechanism\n")); + BTDM_1AntBtCoexist8723A(padapter); + } + + if (!BTDM_IsSameCoexistState(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Coexist State[bitMap] change from 0x%"i64fmt"x to 0x%"i64fmt"x\n", + pHalData->bt_coexist.PreviousState, + pHalData->bt_coexist.CurrentState)); + pHalData->bt_coexist.PreviousState = pHalData->bt_coexist.CurrentState; + + RTPRINT(FBT, BT_TRACE, ("[")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT30) + RTPRINT(FBT, BT_TRACE, ("BT 3.0, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_HT20) + RTPRINT(FBT, BT_TRACE, ("HT20, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_HT40) + RTPRINT(FBT, BT_TRACE, ("HT40, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_LEGACY) + RTPRINT(FBT, BT_TRACE, ("Legacy, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_LOW) + RTPRINT(FBT, BT_TRACE, ("Rssi_Low, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_MEDIUM) + RTPRINT(FBT, BT_TRACE, ("Rssi_Mid, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_HIGH) + RTPRINT(FBT, BT_TRACE, ("Rssi_High, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_IDLE) + RTPRINT(FBT, BT_TRACE, ("Wifi_Idle, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_UPLINK) + RTPRINT(FBT, BT_TRACE, ("Wifi_Uplink, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_DOWNLINK) + RTPRINT(FBT, BT_TRACE, ("Wifi_Downlink, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_IDLE) + RTPRINT(FBT, BT_TRACE, ("BT_idle, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_HID) + RTPRINT(FBT, BT_TRACE, ("PRO_HID, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_A2DP) + RTPRINT(FBT, BT_TRACE, ("PRO_A2DP, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_PAN) + RTPRINT(FBT, BT_TRACE, ("PRO_PAN, ")); + if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_SCO) + RTPRINT(FBT, BT_TRACE, ("PRO_SCO, ")); + RTPRINT(FBT, BT_TRACE, ("]\n")); + } +} + +/* extern function start with BTDM_ */ +u32 BTDM_BtTxRxCounterH(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 counters = 0; + + counters = pHalData->bt_coexist.halCoex8723.highPriorityTx+ + pHalData->bt_coexist.halCoex8723.highPriorityRx; + return counters; +} + +u32 BTDM_BtTxRxCounterL(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 counters = 0; + + counters = pHalData->bt_coexist.halCoex8723.lowPriorityTx+ + pHalData->bt_coexist.halCoex8723.lowPriorityRx ; + return counters; +} + +void BTDM_SetFwChnlInfo(struct rtw_adapter *padapter, enum rt_media_status mstatus) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 H2C_Parameter[3] = {0}; + u8 chnl; + + /* opMode */ + if (RT_MEDIA_CONNECT == mstatus) + H2C_Parameter[0] = 0x1; /* 0: disconnected, 1:connected */ + + if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) { + /* channel */ + chnl = pmlmeext->cur_channel; + if (BTDM_IsHT40(padapter)) { + if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + chnl -= 2; + else if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + chnl += 2; + } + H2C_Parameter[1] = chnl; + } else { /* check if HS link is exists */ + /* channel */ + if (BT_Operation(padapter)) + H2C_Parameter[1] = pBtMgnt->BTChannel; + else + H2C_Parameter[1] = pmlmeext->cur_channel; + } + + if (BTDM_IsHT40(padapter)) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + + FillH2CCmd(padapter, 0x19, 3, H2C_Parameter); +} + +u8 BTDM_IsWifiConnectionExist(struct rtw_adapter *padapter) +{ + u8 bRet = false; + + if (BTHCI_HsConnectionEstablished(padapter)) + bRet = true; + + if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == true) + bRet = true; + + return bRet; +} + +void BTDM_SetFw3a( + struct rtw_adapter *padapter, + u8 byte1, + u8 byte2, + u8 byte3, + u8 byte4, + u8 byte5 + ) +{ + u8 H2C_Parameter[5] = {0}; + + if (BTDM_1Ant8723A(padapter)) { + if ((!check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) && + (get_fwstate(&padapter->mlmepriv) != WIFI_NULL_STATE)) { + /* for softap mode */ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723; + u8 BtState = pBtCoex->c2hBtInfo; + + if ((BtState != BT_INFO_STATE_NO_CONNECTION) && + (BtState != BT_INFO_STATE_CONNECT_IDLE)) { + if (byte1 & BIT(4)) { + byte1 &= ~BIT(4); + byte1 |= BIT(5); + } + + byte5 |= BIT(5); + if (byte5 & BIT(6)) + byte5 &= ~BIT(6); + } + } + } + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], FW write 0x3a(5bytes) = 0x%02x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + FillH2CCmd(padapter, 0x3a, 5, H2C_Parameter); +} + +void BTDM_QueryBtInformation(struct rtw_adapter *padapter) +{ + u8 H2C_Parameter[1] = {0}; + struct hal_data_8723a *pHalData; + struct bt_coexist_8723a *pBtCoex; + + pHalData = GET_HAL_DATA(padapter); + pBtCoex = &pHalData->bt_coexist.halCoex8723; + + if (BT_IsBtDisabled(padapter)) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED; + pBtCoex->bC2hBtInfoReqSent = false; + return; + } + + if (pBtCoex->c2hBtInfo == BT_INFO_STATE_DISABLED) + pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION; + + if (pBtCoex->bC2hBtInfoReqSent == true) + RTPRINT(FBT, BT_TRACE, ("[BTCoex], didn't recv previous BtInfo report!\n")); + else + pBtCoex->bC2hBtInfoReqSent = true; + + H2C_Parameter[0] |= BIT(0); /* trigger */ + +/*RTPRINT(FBT, BT_TRACE, ("[BTCoex], Query Bt information, write 0x38 = 0x%x\n", */ +/*H2C_Parameter[0])); */ + + FillH2CCmd(padapter, 0x38, 1, H2C_Parameter); +} + +void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter *padapter, u8 type) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (BT_RF_RX_LPF_CORNER_SHRINK == type) { + /* Shrink RF Rx LPF corner */ + RTPRINT(FBT, BT_TRACE, ("Shrink RF Rx LPF corner!!\n")); + PHY_SetRFReg(padapter, PathA, 0x1e, bRFRegOffsetMask, 0xf0ff7); + pHalData->bt_coexist.bSWCoexistAllOff = false; + } else if (BT_RF_RX_LPF_CORNER_RESUME == type) { + /* Resume RF Rx LPF corner */ + RTPRINT(FBT, BT_TRACE, ("Resume RF Rx LPF corner!!\n")); + PHY_SetRFReg(padapter, PathA, 0x1e, bRFRegOffsetMask, pHalData->bt_coexist.BtRfRegOrigin1E); + } +} + +void +BTDM_SetSwPenaltyTxRateAdaptive( + struct rtw_adapter *padapter, + u8 raType + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 tmpU1; + + tmpU1 = rtw_read8(padapter, 0x4fd); + tmpU1 |= BIT(0); + if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == raType) { + tmpU1 &= ~BIT(2); + pHalData->bt_coexist.bSWCoexistAllOff = false; + } else if (BT_TX_RATE_ADAPTIVE_NORMAL == raType) { + tmpU1 |= BIT(2); + } + + rtw_write8(padapter, 0x4fd, tmpU1); +} + +void BTDM_SetFwDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[1] = {0}; + + H2C_Parameter[0] = 0; + + if (bDecBtPwr) { + H2C_Parameter[0] |= BIT(1); + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], decrease Bt Power : %s, write 0x21 = 0x%x\n", + (bDecBtPwr ? "Yes!!" : "No!!"), H2C_Parameter[0])); + + FillH2CCmd(padapter, 0x21, 1, H2C_Parameter); +} + +u8 BTDM_BtProfileSupport(struct rtw_adapter *padapter) +{ + u8 bRet = false; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pBtMgnt->bSupportProfile && + !pHalData->bt_coexist.halCoex8723.bForceFwBtInfo) + bRet = true; + + return bRet; +} + +static void BTDM_AdjustForBtOperation8723A(struct rtw_adapter *padapter) +{ + /* BTDM_2AntAdjustForBtOperation8723(padapter); */ +} + +static void BTDM_FwC2hBtRssi8723A(struct rtw_adapter *padapter, u8 *tmpBuf) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 percent = 0, u1tmp = 0; + + u1tmp = tmpBuf[0]; + percent = u1tmp*2+10; + + pHalData->bt_coexist.halCoex8723.btRssi = percent; +/*RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT RSSI =%d\n", percent)); */ +} + +static void +BTDM_FwC2hBtInfo8723A(struct rtw_adapter *padapter, u8 *tmpBuf, u8 length) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_coexist_8723a *pBtCoex; + u8 i; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtCoex = &pHalData->bt_coexist.halCoex8723; + + pBtCoex->bC2hBtInfoReqSent = false; + + RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT info[%d]=[", length)); + + pBtCoex->btRetryCnt = 0; + for (i = 0; i < length; i++) { + switch (i) { + case 0: + pBtCoex->c2hBtInfoOriginal = tmpBuf[i]; + break; + case 1: + pBtCoex->btRetryCnt = tmpBuf[i]; + break; + case 2: + BTDM_FwC2hBtRssi8723A(padapter, &tmpBuf[i]); + break; + case 3: + pBtCoex->btInfoExt = tmpBuf[i]&BIT(0); + break; + } + + if (i == length-1) + RTPRINT(FBT, BT_TRACE, ("0x%02x]\n", tmpBuf[i])); + else + RTPRINT(FBT, BT_TRACE, ("0x%02x, ", tmpBuf[i])); + } + RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT RSSI =%d\n", pBtCoex->btRssi)); + if (pBtCoex->btInfoExt) + RTPRINT(FBT, BT_TRACE, ("[BTC2H], pBtCoex->btInfoExt =%x\n", pBtCoex->btInfoExt)); + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntFwC2hBtInfo8723A(padapter); + else + BTDM_2AntFwC2hBtInfo8723A(padapter); + + if (pBtMgnt->ExtConfig.bManualControl) { + RTPRINT(FBT, BT_TRACE, ("%s: Action Manual control!!\n", __func__)); + return; + } + + btdm_BTCoexist8723AHandler(padapter); +} + +static void BTDM_Display8723ABtCoexInfo(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 u1Tmp, u1Tmp1, u1Tmp2, i, btInfoExt, psTdmaCase = 0; + u32 u4Tmp[4]; + u8 antNum = Ant_x2; + + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + DCMD_Printf(btCoexDbgBuf); + + if (!pHalData->bt_coexist.BluetoothCoexist) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + DCMD_Printf(btCoexDbgBuf); + return; + } + + antNum = btdm_BtWifiAntNum(padapter); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/%d ", "Ant mechanism PG/Now run :", \ + ((pHalData->bt_coexist.BT_Ant_Num == Ant_x2) ? 2 : 1), ((antNum == Ant_x2) ? 2 : 1)); + DCMD_Printf(btCoexDbgBuf); + + if (pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + DCMD_Printf(btCoexDbgBuf); + } else { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pBtMgnt->bSupportProfile) ? "Yes" : "No"), pBtMgnt->ExtConfig.HCIExtensionVer); + DCMD_Printf(btCoexDbgBuf); + } + + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = / %d", "Dot11 channel / BT channel", \ + pBtMgnt->BTChannel); + DCMD_Printf(btCoexDbgBuf); + + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = %d / %d / %d", "Wifi/BT/HS rssi", \ + BTDM_GetRxSS(padapter), + pHalData->bt_coexist.halCoex8723.btRssi, + pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB); + DCMD_Printf(btCoexDbgBuf); + + if (!pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %s ", "WIfi status", + ((BTDM_Legacy(padapter)) ? "Legacy" : (((BTDM_IsHT40(padapter)) ? "HT40" : "HT20"))), + ((!BTDM_IsWifiBusy(padapter)) ? "idle" : ((BTDM_IsWifiUplink(padapter)) ? "uplink" : "downlink"))); + DCMD_Printf(btCoexDbgBuf); + + if (pBtMgnt->bSupportProfile) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", + ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_SCO)) ? 1 : 0), + ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) ? 1 : 0), + ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) ? 1 : 0), + ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) ? 1 : 0)); + DCMD_Printf(btCoexDbgBuf); + + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) { + if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", "Bt link type/spec/role", + BtProfileString[pBtMgnt->ExtConfig.linkInfo[i].BTProfile], + BtSpecString[pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec], + BtLinkRoleString[pBtMgnt->ExtConfig.linkInfo[i].linkRole]); + DCMD_Printf(btCoexDbgBuf); + + btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt; + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "A2DP rate", \ + (btInfoExt&BIT0) ? "Basic rate" : "EDR rate"); + DCMD_Printf(btCoexDbgBuf); + } else { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", "Bt link type/spec", \ + BtProfileString[pBtMgnt->ExtConfig.linkInfo[i].BTProfile], + BtSpecString[pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec]); + DCMD_Printf(btCoexDbgBuf); + } + } + } + } + + /* Sw mechanism */ + if (!pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw BT Coex mechanism]============"); + DCMD_Printf(btCoexDbgBuf); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "AGC Table", \ + pBtCoex->btdm2Ant.bCurAgcTableEn); + DCMD_Printf(btCoexDbgBuf); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "ADC Backoff", \ + pBtCoex->btdm2Ant.bCurAdcBackOff); + DCMD_Printf(btCoexDbgBuf); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "Low penalty RA", \ + pBtCoex->btdm2Ant.bCurLowPenaltyRa); + DCMD_Printf(btCoexDbgBuf); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "RF Rx LPF Shrink", \ + pBtCoex->btdm2Ant.bCurRfRxLpfShrink); + DCMD_Printf(btCoexDbgBuf); + } + u4Tmp[0] = PHY_QueryRFReg(padapter, PathA, 0x1e, 0xff0); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "RF-A, 0x1e[11:4]/original val", \ + u4Tmp[0], pHalData->bt_coexist.BtRfRegOrigin1E); + DCMD_Printf(btCoexDbgBuf); + + /* Fw mechanism */ + if (!pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw BT Coex mechanism]============"); + DCMD_Printf(btCoexDbgBuf); + } + if (!pBtMgnt->ExtConfig.bManualControl) { + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + psTdmaCase = pHalData->bt_coexist.halCoex8723.btdm1Ant.curPsTdma; + else + psTdmaCase = pHalData->bt_coexist.halCoex8723.btdm2Ant.curPsTdma; + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA(0x3a)", \ + pHalData->bt_coexist.fw3aVal[0], pHalData->bt_coexist.fw3aVal[1], + pHalData->bt_coexist.fw3aVal[2], pHalData->bt_coexist.fw3aVal[3], + pHalData->bt_coexist.fw3aVal[4], psTdmaCase); + DCMD_Printf(btCoexDbgBuf); + + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "Decrease Bt Power", \ + pBtCoex->btdm2Ant.bCurDecBtPwr); + DCMD_Printf(btCoexDbgBuf); + } + u1Tmp = rtw_read8(padapter, 0x778); + u1Tmp1 = rtw_read8(padapter, 0x783); + u1Tmp2 = rtw_read8(padapter, 0x796); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \ + u1Tmp, u1Tmp1, u1Tmp2); + DCMD_Printf(btCoexDbgBuf); + + if (!pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x / 0x%x", "Sw DacSwing Ctrl/Val", \ + pBtCoex->btdm2Ant.bCurDacSwingOn, pBtCoex->btdm2Ant.curDacSwingLvl); + DCMD_Printf(btCoexDbgBuf); + } + u4Tmp[0] = rtw_read32(padapter, 0x880); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \ + u4Tmp[0]); + DCMD_Printf(btCoexDbgBuf); + + /* Hw mechanism */ + if (!pBtMgnt->ExtConfig.bManualControl) { + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw BT Coex mechanism]============"); + DCMD_Printf(btCoexDbgBuf); + } + + u1Tmp = rtw_read8(padapter, 0x40); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp); + DCMD_Printf(btCoexDbgBuf); + + u4Tmp[0] = rtw_read32(padapter, 0x550); + u1Tmp = rtw_read8(padapter, 0x522); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x", "0x550(bcn contrl)/0x522", \ + u4Tmp[0], u1Tmp); + DCMD_Printf(btCoexDbgBuf); + + u4Tmp[0] = rtw_read32(padapter, 0x484); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \ + u4Tmp[0]); + DCMD_Printf(btCoexDbgBuf); + + u4Tmp[0] = rtw_read32(padapter, 0x50); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + DCMD_Printf(btCoexDbgBuf); + + u4Tmp[0] = rtw_read32(padapter, 0xda0); + u4Tmp[1] = rtw_read32(padapter, 0xda4); + u4Tmp[2] = rtw_read32(padapter, 0xda8); + u4Tmp[3] = rtw_read32(padapter, 0xdac); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]); + DCMD_Printf(btCoexDbgBuf); + + u4Tmp[0] = rtw_read32(padapter, 0x6c0); + u4Tmp[1] = rtw_read32(padapter, 0x6c4); + u4Tmp[2] = rtw_read32(padapter, 0x6c8); + u1Tmp = rtw_read8(padapter, 0x6cc); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp); + DCMD_Printf(btCoexDbgBuf); + + /* u4Tmp = rtw_read32(padapter, 0x770); */ + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d", "0x770(Hi pri Rx[31:16]/Tx[15:0])", \ + pHalData->bt_coexist.halCoex8723.highPriorityRx, + pHalData->bt_coexist.halCoex8723.highPriorityTx); + DCMD_Printf(btCoexDbgBuf); + /* u4Tmp = rtw_read32(padapter, 0x774); */ + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d", "0x774(Lo pri Rx[31:16]/Tx[15:0])", \ + pHalData->bt_coexist.halCoex8723.lowPriorityRx, + pHalData->bt_coexist.halCoex8723.lowPriorityTx); + DCMD_Printf(btCoexDbgBuf); + + /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang */ + u1Tmp = rtw_read8(padapter, 0x41b); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (hang chk == 0xf)", \ + u1Tmp); + DCMD_Printf(btCoexDbgBuf); + rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "lastHMEBoxNum", \ + pHalData->LastHMEBoxNum); + DCMD_Printf(btCoexDbgBuf); +} + +static void +BTDM_8723ASignalCompensation(struct rtw_adapter *padapter, + u8 *rssi_wifi, u8 *rssi_bt) +{ + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntSignalCompensation(padapter, rssi_wifi, rssi_bt); +} + +static void BTDM_8723AInit(struct rtw_adapter *padapter) +{ + if (btdm_BtWifiAntNum(padapter) == Ant_x2) + BTDM_2AntParaInit(padapter); + else + BTDM_1AntParaInit(padapter); +} + +static void BTDM_HWCoexAllOff8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x2) + BTDM_2AntHwCoexAllOff8723A(padapter); +} + +static void BTDM_FWCoexAllOff8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x2) + BTDM_2AntFwCoexAllOff8723A(padapter); +} + +static void BTDM_SWCoexAllOff8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x2) + BTDM_2AntSwCoexAllOff8723A(padapter); +} + +static void +BTDM_Set8723ABtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723; + + if (antNum == 1) + pBtCoex->TotalAntNum = Ant_x1; + else if (antNum == 2) + pBtCoex->TotalAntNum = Ant_x2; +} + +void BTDM_LpsLeave(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntLpsLeave(padapter); +} + +static void BTDM_ForHalt8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntForHalt(padapter); +} + +static void BTDM_WifiScanNotify8723A(struct rtw_adapter *padapter, u8 scanType) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntWifiScanNotify(padapter, scanType); +} + +static void +BTDM_WifiAssociateNotify8723A(struct rtw_adapter *padapter, u8 action) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntWifiAssociateNotify(padapter, action); +} + +static void +BTDM_MediaStatusNotify8723A(struct rtw_adapter *padapter, + enum rt_media_status mstatus) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], MediaStatusNotify, %s\n", + mstatus?"connect":"disconnect")); + + BTDM_SetFwChnlInfo(padapter, mstatus); + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntMediaStatusNotify(padapter, mstatus); +} + +static void BTDM_ForDhcp8723A(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bManualControl) + return; + + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + BTDM_1AntForDhcp(padapter); +} + +u8 BTDM_1Ant8723A(struct rtw_adapter *padapter) +{ + if (btdm_BtWifiAntNum(padapter) == Ant_x1) + return true; + else + return false; +} + +static void BTDM_BTCoexist8723A(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_coexist_8723a *pBtCoex; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtCoex = &pHalData->bt_coexist.halCoex8723; + + RTPRINT(FBT, BT_TRACE, ("[BTCoex], beacon RSSI = 0x%x(%d)\n", + pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB, + pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB)); + + btdm_BtHwCountersMonitor(padapter); + btdm_BtEnableDisableCheck8723A(padapter); + + if (pBtMgnt->ExtConfig.bManualControl) { + RTPRINT(FBT, BT_TRACE, ("%s: Action Manual control!!\n", __func__)); + return; + } + + if (pBtCoex->bC2hBtInfoReqSent) { + if (BT_IsBtDisabled(padapter)) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED; + } else { + if (pBtCoex->c2hBtInfo == BT_INFO_STATE_DISABLED) + pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION; + } + + btdm_BTCoexist8723AHandler(padapter); + } else if (BT_IsBtDisabled(padapter) == true) { + pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED; + btdm_BTCoexist8723AHandler(padapter); + } + + BTDM_QueryBtInformation(padapter); +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.c ===== */ +#endif + +#ifdef __HALBTCCSR1ANT_C__ /* HAL/BTCoexist/HalBtcCsr1Ant.c */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.c ===== */ + +/* local function start with btdm_ */ +/* extern function start with BTDM_ */ + +static void BTDM_SetAntenna(struct rtw_adapter *padapter, u8 who) +{ +} + +void +BTDM_SingleAnt( + struct rtw_adapter *padapter, + u8 bSingleAntOn, + u8 bInterruptOn, + u8 bMultiNAVOn + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[3] = {0}; + + if (pHalData->bt_coexist.BT_Ant_Num != Ant_x1) + return; + + H2C_Parameter[2] = 0; + H2C_Parameter[1] = 0; + H2C_Parameter[0] = 0; + + if (bInterruptOn) { + H2C_Parameter[2] |= 0x02; /* BIT1 */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + pHalData->bt_coexist.bInterruptOn = bInterruptOn; + + if (bSingleAntOn) { + H2C_Parameter[2] |= 0x10; /* BIT4 */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + pHalData->bt_coexist.bSingleAntOn = bSingleAntOn; + + if (bMultiNAVOn) { + H2C_Parameter[2] |= 0x20; /* BIT5 */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + pHalData->bt_coexist.bMultiNAVOn = bMultiNAVOn; + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], SingleAntenna =[%s:%s:%s], write 0xe = 0x%x\n", + bSingleAntOn?"ON":"OFF", bInterruptOn?"ON":"OFF", bMultiNAVOn?"ON":"OFF", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); +} + +void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + u8 stateChange = false; + u32 BT_Polling, Ratio_Act, Ratio_STA; + u32 BT_Active, BT_State; + u32 regBTActive = 0, regBTState = 0, regBTPolling = 0; + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + if (pBtMgnt->ExtConfig.bManualControl) + return; + if (pHalData->bt_coexist.BT_CoexistType != BT_CSR_BC8) + return; + if (pHalData->bt_coexist.BT_Ant_Num != Ant_x1) + return; + + /* The following we only consider CSR BC8 and fw version should be >= 62 */ + RTPRINT(FBT, BT_TRACE, ("[DM][BT], FirmwareVersion = 0x%x(%d)\n", + pHalData->FirmwareVersion, pHalData->FirmwareVersion)); + regBTActive = REG_BT_ACTIVE; + regBTState = REG_BT_STATE; + if (pHalData->FirmwareVersion >= FW_VER_BT_REG1) + regBTPolling = REG_BT_POLLING1; + else + regBTPolling = REG_BT_POLLING; + + BT_Active = rtw_read32(padapter, regBTActive); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_Active(0x%x) =%x\n", regBTActive, BT_Active)); + BT_Active = BT_Active & 0x00ffffff; + + BT_State = rtw_read32(padapter, regBTState); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_State(0x%x) =%x\n", regBTState, BT_State)); + BT_State = BT_State & 0x00ffffff; + + BT_Polling = rtw_read32(padapter, regBTPolling); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_Polling(0x%x) =%x\n", regBTPolling, BT_Polling)); + + if (BT_Active == 0xffffffff && BT_State == 0xffffffff && BT_Polling == 0xffffffff) + return; + if (BT_Polling == 0) + return; + + Ratio_Act = BT_Active*1000/BT_Polling; + Ratio_STA = BT_State*1000/BT_Polling; + + pHalData->bt_coexist.Ratio_Tx = Ratio_Act; + pHalData->bt_coexist.Ratio_PRI = Ratio_STA; + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], Ratio_Act =%d\n", Ratio_Act)); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], Ratio_STA =%d\n", Ratio_STA)); + + if (Ratio_STA < 60 && Ratio_Act < 500) { /* BT PAN idle */ + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_IDLE; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_DOWNLINK; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK; + } else { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_IDLE; + + if (Ratio_STA) { + /* Check if BT PAN (under BT 2.1) is uplink or downlink */ + if ((Ratio_Act/Ratio_STA) < 2) { + /* BT PAN Uplink */ + pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = true; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_UPLINK; + pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = false; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_DOWNLINK; + } else { + /* BT PAN downlink */ + pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = false; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK; + pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = true; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_DOWNLINK; + } + } else { + /* BT PAN downlink */ + pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = false; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK; + pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = true; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_DOWNLINK; + } + } + + /* Check BT is idle or not */ + if (pBtMgnt->ExtConfig.NumberOfHandle == 0 && + pBtMgnt->ExtConfig.NumberOfSCO == 0) { + pBtMgnt->ExtConfig.bBTBusy = false; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE; + } else { + if (Ratio_STA < 60) { + pBtMgnt->ExtConfig.bBTBusy = false; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE; + } else { + pBtMgnt->ExtConfig.bBTBusy = true; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_IDLE; + } + } + + if (pBtMgnt->ExtConfig.NumberOfHandle == 0 && + pBtMgnt->ExtConfig.NumberOfSCO == 0) { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_RSSI_LOW; + pBtMgnt->ExtConfig.MIN_BT_RSSI = 0; + BTDM_SetAntenna(padapter, BTDM_ANT_BT_IDLE); + } else { + if (pBtMgnt->ExtConfig.MIN_BT_RSSI <= -5) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_RSSI_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], core stack notify bt rssi Low\n")); + } else { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_RSSI_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], core stack notify bt rssi Normal\n")); + } + } + + if (pHalData->bt_coexist.bBTBusyTraffic != pBtMgnt->ExtConfig.bBTBusy) { + /* BT idle or BT non-idle */ + pHalData->bt_coexist.bBTBusyTraffic = pBtMgnt->ExtConfig.bBTBusy; + stateChange = true; + } + + if (stateChange) { + if (!pBtMgnt->ExtConfig.bBTBusy) + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is idle or disable\n")); + else + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is non-idle\n")); + } + if (!pBtMgnt->ExtConfig.bBTBusy) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is idle or disable\n")); + if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING|WIFI_SITE_MONITOR) == true) + BTDM_SetAntenna(padapter, BTDM_ANT_WIFI); + } +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.c ===== */ +#endif + +#ifdef __HALBTCCSR2ANT_C__ /* HAL/BTCoexist/HalBtcCsr2Ant.c */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.c ===== */ + +/* local function start with btdm_ */ + +/* Note: */ +/* In the following, FW should be done before SW mechanism. */ +/* BTDM_Balance(), BTDM_DiminishWiFi(), BT_NAV() should be done */ +/* before BTDM_AGCTable(), BTDM_BBBackOffLevel(), btdm_DacSwing(). */ + +/* extern function start with BTDM_ */ + +void +BTDM_DiminishWiFi( + struct rtw_adapter *padapter, + u8 bDACOn, + u8 bInterruptOn, + u8 DACSwingLevel, + u8 bNAVOn + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[3] = {0}; + + if (pHalData->bt_coexist.BT_Ant_Num != Ant_x2) + return; + + if ((pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_RSSI_LOW) && + (DACSwingLevel == 0x20)) { + RTPRINT(FBT, BT_TRACE, ("[BT]DiminishWiFi 0x20 original, but set 0x18 for Low RSSI!\n")); + DACSwingLevel = 0x18; + } + + H2C_Parameter[2] = 0; + H2C_Parameter[1] = DACSwingLevel; + H2C_Parameter[0] = 0; + if (bDACOn) { + H2C_Parameter[2] |= 0x01; /* BIT0 */ + if (bInterruptOn) + H2C_Parameter[2] |= 0x02; /* BIT1 */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + if (bNAVOn) { + H2C_Parameter[2] |= 0x08; /* BIT3 */ + pHalData->bt_coexist.bFWCoexistAllOff = false; + } + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], bDACOn = %s, bInterruptOn = %s, write 0xe = 0x%x\n", + bDACOn?"ON":"OFF", bInterruptOn?"ON":"OFF", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], bNAVOn = %s\n", + bNAVOn?"ON":"OFF")); +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.c ===== */ +#endif + +#ifdef __HALBTCOEXIST_C__ /* HAL/BTCoexist/HalBtCoexist.c */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtCoexist.c ===== */ + +/* local function */ +static void btdm_ResetFWCoexState(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->bt_coexist.CurrentState = 0; + pHalData->bt_coexist.PreviousState = 0; +} + +static void btdm_InitBtCoexistDM(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* 20100415 Joseph: Restore RF register 0x1E and 0x1F value for further usage. */ + pHalData->bt_coexist.BtRfRegOrigin1E = PHY_QueryRFReg(padapter, PathA, RF_RCK1, bRFRegOffsetMask); + pHalData->bt_coexist.BtRfRegOrigin1F = PHY_QueryRFReg(padapter, PathA, RF_RCK2, 0xf0); + + pHalData->bt_coexist.CurrentState = 0; + pHalData->bt_coexist.PreviousState = 0; + + BTDM_8723AInit(padapter); + pHalData->bt_coexist.bInitlized = true; +} + +/* */ +/* extern function */ +/* */ +void BTDM_CheckAntSelMode(struct rtw_adapter *padapter) +{ +} + +void BTDM_FwC2hBtRssi(struct rtw_adapter *padapter, u8 *tmpBuf) +{ + BTDM_FwC2hBtRssi8723A(padapter, tmpBuf); +} + +void BTDM_FwC2hBtInfo(struct rtw_adapter *padapter, u8 *tmpBuf, u8 length) +{ + BTDM_FwC2hBtInfo8723A(padapter, tmpBuf, length); +} + +void BTDM_DisplayBtCoexInfo(struct rtw_adapter *padapter) +{ + BTDM_Display8723ABtCoexInfo(padapter); +} + +void BTDM_RejectAPAggregatedPacket(struct rtw_adapter *padapter, u8 bReject) +{ +} + +u8 BTDM_IsHT40(struct rtw_adapter *padapter) +{ + u8 isht40 = true; + enum ht_channel_width bw; + + bw = padapter->mlmeextpriv.cur_bwmode; + + if (bw == HT_CHANNEL_WIDTH_20) + isht40 = false; + else if (bw == HT_CHANNEL_WIDTH_40) + isht40 = true; + + return isht40; +} + +u8 BTDM_Legacy(struct rtw_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext; + u8 isLegacy = false; + + pmlmeext = &padapter->mlmeextpriv; + if ((pmlmeext->cur_wireless_mode == WIRELESS_11B) || + (pmlmeext->cur_wireless_mode == WIRELESS_11G) || + (pmlmeext->cur_wireless_mode == WIRELESS_11BG)) + isLegacy = true; + + return isLegacy; +} + +void BTDM_CheckWiFiState(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct mlme_priv *pmlmepriv; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + + pHalData = GET_HAL_DATA(padapter); + pmlmepriv = &padapter->mlmepriv; + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_IDLE; + + if (pmlmepriv->LinkDetectInfo.bTxBusyTraffic) + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_UPLINK; + else + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_UPLINK; + + if (pmlmepriv->LinkDetectInfo.bRxBusyTraffic) + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_DOWNLINK; + else + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_DOWNLINK; + } else { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_IDLE; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_UPLINK; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_DOWNLINK; + } + + if (BTDM_Legacy(padapter)) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_LEGACY; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT20; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT40; + } else { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_LEGACY; + if (BTDM_IsHT40(padapter)) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_HT40; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT20; + } else { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_HT20; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT40; + } + } + + if (pBtMgnt->BtOperationOn) + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT30; + else + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT30; +} + +s32 BTDM_GetRxSS(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct mlme_priv *pmlmepriv; + struct hal_data_8723a *pHalData; + s32 UndecoratedSmoothedPWDB = 0; + + pmlmepriv = &padapter->mlmepriv; + pHalData = GET_HAL_DATA(padapter); + + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + UndecoratedSmoothedPWDB = GET_UNDECORATED_AVERAGE_RSSI(padapter); + } else { /* associated entry pwdb */ + UndecoratedSmoothedPWDB = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB; + /* pHalData->BT_EntryMinUndecoratedSmoothedPWDB */ + } + RTPRINT(FBT, BT_TRACE, ("BTDM_GetRxSS() = %d\n", UndecoratedSmoothedPWDB)); + return UndecoratedSmoothedPWDB; +} + +static s32 BTDM_GetRxBeaconSS(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ + struct mlme_priv *pmlmepriv; + struct hal_data_8723a *pHalData; + s32 pwdbBeacon = 0; + + pmlmepriv = &padapter->mlmepriv; + pHalData = GET_HAL_DATA(padapter); + + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + /* pwdbBeacon = pHalData->dmpriv.UndecoratedSmoothedBeacon; */ + pwdbBeacon = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB; + } + RTPRINT(FBT, BT_TRACE, ("BTDM_GetRxBeaconSS() = %d\n", pwdbBeacon)); + return pwdbBeacon; +} + +/* Get beacon rssi state */ +u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter *padapter, u8 levelNum, + u8 RssiThresh, u8 RssiThresh1) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + s32 pwdbBeacon = 0; + u8 bcnRssiState = 0; + + pwdbBeacon = BTDM_GetRxBeaconSS(padapter); + + if (levelNum == 2) { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM; + + if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_LOW)) { + if (pwdbBeacon >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + bcnRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to High\n")); + } else { + bcnRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Low\n")); + } + } else { + if (pwdbBeacon < RssiThresh) { + bcnRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Low\n")); + } else { + bcnRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at High\n")); + } + } + } else if (levelNum == 3) { + if (RssiThresh > RssiThresh1) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON thresh error!!\n")); + return pHalData->bt_coexist.preRssiStateBeacon; + } + + if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_LOW)) { + if (pwdbBeacon >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + bcnRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Medium\n")); + } else { + bcnRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Low\n")); + } + } else if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_MEDIUM) || + (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_MEDIUM)) { + if (pwdbBeacon >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) { + bcnRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to High\n")); + } else if (pwdbBeacon < RssiThresh) { + bcnRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Low\n")); + } else { + bcnRssiState = BT_RSSI_STATE_STAY_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Medium\n")); + } + } else { + if (pwdbBeacon < RssiThresh1) { + bcnRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Medium\n")); + } else { + bcnRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at High\n")); + } + } + } + + pHalData->bt_coexist.preRssiStateBeacon = bcnRssiState; + + return bcnRssiState; +} + +u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter *padapter, u8 levelNum, + u8 RssiThresh, u8 RssiThresh1) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + s32 UndecoratedSmoothedPWDB = 0; + u8 btRssiState = 0; + + UndecoratedSmoothedPWDB = BTDM_GetRxSS(padapter); + + if (levelNum == 2) { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + + if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_LOW)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to High\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n")); + } + } else { + if (UndecoratedSmoothedPWDB < RssiThresh) { + btRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at High\n")); + } + } + } else if (levelNum == 3) { + if (RssiThresh > RssiThresh1) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 thresh error!!\n")); + return pHalData->bt_coexist.preRssiState1; + } + + if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_LOW)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Medium\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n")); + } + } else if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_MEDIUM) || + (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_MEDIUM)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to High\n")); + } else if (UndecoratedSmoothedPWDB < RssiThresh) { + btRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Medium\n")); + } + } else { + if (UndecoratedSmoothedPWDB < RssiThresh1) { + btRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Medium\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at High\n")); + } + } + } + + pHalData->bt_coexist.preRssiState1 = btRssiState; + + return btRssiState; +} + +u8 BTDM_CheckCoexRSSIState(struct rtw_adapter *padapter, u8 levelNum, + u8 RssiThresh, u8 RssiThresh1) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + s32 UndecoratedSmoothedPWDB = 0; + u8 btRssiState = 0; + + UndecoratedSmoothedPWDB = BTDM_GetRxSS(padapter); + + if (levelNum == 2) { + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + + if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_LOW)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to High\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Low\n")); + } + } else { + if (UndecoratedSmoothedPWDB < RssiThresh) { + btRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Low\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at High\n")); + } + } + } else if (levelNum == 3) { + if (RssiThresh > RssiThresh1) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI thresh error!!\n")); + return pHalData->bt_coexist.preRssiState; + } + + if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_LOW) || + (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_LOW)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Medium\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Low\n")); + } + } else if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_MEDIUM) || + (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_MEDIUM)) { + if (UndecoratedSmoothedPWDB >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) { + btRssiState = BT_RSSI_STATE_HIGH; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to High\n")); + } else if (UndecoratedSmoothedPWDB < RssiThresh) { + btRssiState = BT_RSSI_STATE_LOW; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_LOW; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Low\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_MEDIUM; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Medium\n")); + } + } else { + if (UndecoratedSmoothedPWDB < RssiThresh1) { + btRssiState = BT_RSSI_STATE_MEDIUM; + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_MEDIUM; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH; + pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Medium\n")); + } else { + btRssiState = BT_RSSI_STATE_STAY_HIGH; + RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at High\n")); + } + } + } + + pHalData->bt_coexist.preRssiState = btRssiState; + + return btRssiState; +} + +u8 BTDM_DisableEDCATurbo(struct rtw_adapter *padapter) +{ + struct bt_mgnt *pBtMgnt; + struct hal_data_8723a *pHalData; + u8 bBtChangeEDCA = false; + u32 EDCA_BT_BE = 0x5ea42b, cur_EDCA_reg; + u8 bRet = false; + + pHalData = GET_HAL_DATA(padapter); + pBtMgnt = &pHalData->BtInfo.BtMgnt; + + if (!pHalData->bt_coexist.BluetoothCoexist) { + bRet = false; + pHalData->bt_coexist.lastBtEdca = 0; + return bRet; + } + if (!((pBtMgnt->bSupportProfile) || + (pHalData->bt_coexist.BT_CoexistType == BT_CSR_BC8))) { + bRet = false; + pHalData->bt_coexist.lastBtEdca = 0; + return bRet; + } + + if (BT_1Ant(padapter)) { + bRet = false; + pHalData->bt_coexist.lastBtEdca = 0; + return bRet; + } + + if (pHalData->bt_coexist.exec_cnt < 3) + pHalData->bt_coexist.exec_cnt++; + else + pHalData->bt_coexist.bEDCAInitialized = true; + + /* When BT is non idle */ + if (!(pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_IDLE)) { + RTPRINT(FBT, BT_TRACE, ("BT state non idle, set bt EDCA\n")); + + /* aggr_num = 0x0909; */ + if (pHalData->odmpriv.DM_EDCA_Table.bCurrentTurboEDCA) { + bBtChangeEDCA = true; + pHalData->odmpriv.DM_EDCA_Table.bCurrentTurboEDCA = false; + pHalData->dmpriv.prv_traffic_idx = 3; + } + cur_EDCA_reg = rtw_read32(padapter, REG_EDCA_BE_PARAM); + + if (cur_EDCA_reg != EDCA_BT_BE) + bBtChangeEDCA = true; + if (bBtChangeEDCA || !pHalData->bt_coexist.bEDCAInitialized) { + rtw_write32(padapter, REG_EDCA_BE_PARAM, EDCA_BT_BE); + pHalData->bt_coexist.lastBtEdca = EDCA_BT_BE; + } + bRet = true; + } else { + RTPRINT(FBT, BT_TRACE, ("BT state idle, set original EDCA\n")); + pHalData->bt_coexist.lastBtEdca = 0; + bRet = false; + } + return bRet; +} + +void +BTDM_Balance( + struct rtw_adapter *padapter, + u8 bBalanceOn, + u8 ms0, + u8 ms1 + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[3] = {0}; + + if (bBalanceOn) { + H2C_Parameter[2] = 1; + H2C_Parameter[1] = ms1; + H2C_Parameter[0] = ms0; + pHalData->bt_coexist.bFWCoexistAllOff = false; + } else { + H2C_Parameter[2] = 0; + H2C_Parameter[1] = 0; + H2C_Parameter[0] = 0; + } + pHalData->bt_coexist.bBalanceOn = bBalanceOn; + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], Balance =[%s:%dms:%dms], write 0xc = 0x%x\n", + bBalanceOn?"ON":"OFF", ms0, ms1, + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + FillH2CCmd(padapter, 0xc, 3, H2C_Parameter); +} + +void BTDM_AGCTable(struct rtw_adapter *padapter, u8 type) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + if (type == BT_AGCTABLE_OFF) { + RTPRINT(FBT, BT_TRACE, ("[BT]AGCTable Off!\n")); + rtw_write32(padapter, 0xc78, 0x641c0001); + rtw_write32(padapter, 0xc78, 0x631d0001); + rtw_write32(padapter, 0xc78, 0x621e0001); + rtw_write32(padapter, 0xc78, 0x611f0001); + rtw_write32(padapter, 0xc78, 0x60200001); + + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x32000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x71000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xb0000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xfc000); + PHY_SetRFReg(padapter, PathA, RF_RX_G1, bRFRegOffsetMask, 0x30355); + + pHalData->bt_coexist.b8723aAgcTableOn = false; + } else if (type == BT_AGCTABLE_ON) { + RTPRINT(FBT, BT_TRACE, ("[BT]AGCTable On!\n")); + rtw_write32(padapter, 0xc78, 0x4e1c0001); + rtw_write32(padapter, 0xc78, 0x4d1d0001); + rtw_write32(padapter, 0xc78, 0x4c1e0001); + rtw_write32(padapter, 0xc78, 0x4b1f0001); + rtw_write32(padapter, 0xc78, 0x4a200001); + + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xdc000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x90000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x51000); + PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x12000); + PHY_SetRFReg(padapter, PathA, RF_RX_G1, bRFRegOffsetMask, 0x00355); + + pHalData->bt_coexist.b8723aAgcTableOn = true; + + pHalData->bt_coexist.bSWCoexistAllOff = false; + } +} + +void BTDM_BBBackOffLevel(struct rtw_adapter *padapter, u8 type) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (type == BT_BB_BACKOFF_OFF) { + RTPRINT(FBT, BT_TRACE, ("[BT]BBBackOffLevel Off!\n")); + rtw_write32(padapter, 0xc04, 0x3a05611); + } else if (type == BT_BB_BACKOFF_ON) { + RTPRINT(FBT, BT_TRACE, ("[BT]BBBackOffLevel On!\n")); + rtw_write32(padapter, 0xc04, 0x3a07611); + pHalData->bt_coexist.bSWCoexistAllOff = false; + } +} + +void BTDM_FWCoexAllOff(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);; + + RTPRINT(FBT, BT_TRACE, ("BTDM_FWCoexAllOff()\n")); + if (pHalData->bt_coexist.bFWCoexistAllOff) + return; + RTPRINT(FBT, BT_TRACE, ("BTDM_FWCoexAllOff(), real Do\n")); + + BTDM_FWCoexAllOff8723A(padapter); + + pHalData->bt_coexist.bFWCoexistAllOff = true; +} + +void BTDM_SWCoexAllOff(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);; + + RTPRINT(FBT, BT_TRACE, ("BTDM_SWCoexAllOff()\n")); + if (pHalData->bt_coexist.bSWCoexistAllOff) + return; + RTPRINT(FBT, BT_TRACE, ("BTDM_SWCoexAllOff(), real Do\n")); + BTDM_SWCoexAllOff8723A(padapter); + + pHalData->bt_coexist.bSWCoexistAllOff = true; +} + +void BTDM_HWCoexAllOff(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);; + + RTPRINT(FBT, BT_TRACE, ("BTDM_HWCoexAllOff()\n")); + if (pHalData->bt_coexist.bHWCoexistAllOff) + return; + RTPRINT(FBT, BT_TRACE, ("BTDM_HWCoexAllOff(), real Do\n")); + + BTDM_HWCoexAllOff8723A(padapter); + + pHalData->bt_coexist.bHWCoexistAllOff = true; +} + +void BTDM_CoexAllOff(struct rtw_adapter *padapter) +{ + BTDM_FWCoexAllOff(padapter); + BTDM_SWCoexAllOff(padapter); + BTDM_HWCoexAllOff(padapter); +} + +void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct pwrctrl_priv *ppwrctrl = &padapter->pwrctrlpriv; + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + /* 8723 1Ant doesn't need to turn off bt coexist mechanism. */ + if (BTDM_1Ant8723A(padapter)) + return; + + /* Before enter IPS, turn off FW BT Co-exist mechanism */ + if (ppwrctrl->reg_rfoff == rf_on) { + RTPRINT(FBT, BT_TRACE, ("[BT][DM], Before enter IPS, turn off all Coexist DM\n")); + btdm_ResetFWCoexState(padapter); + BTDM_CoexAllOff(padapter); + BTDM_SetAntenna(padapter, BTDM_ANT_BT); + } +} + +void BTDM_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt) +{ + BTDM_8723ASignalCompensation(padapter, rssi_wifi, rssi_bt); +} + +void BTDM_Coexist(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT not exists!!\n")); + return; + } + + if (!pHalData->bt_coexist.bInitlized) { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], btdm_InitBtCoexistDM()\n")); + btdm_InitBtCoexistDM(padapter); + } + + RTPRINT(FBT, BT_TRACE, ("\n\n[DM][BT], BTDM start!!\n")); + + BTDM_PWDBMonitor(padapter); + + RTPRINT(FBT, BT_TRACE, ("[DM][BT], HW type is 8723\n")); + BTDM_BTCoexist8723A(padapter); + RTPRINT(FBT, BT_TRACE, ("[DM][BT], BTDM end!!\n\n")); +} + +void BTDM_UpdateCoexState(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!BTDM_IsSameCoexistState(padapter)) { + RTPRINT(FBT, BT_TRACE, ("[BTCoex], Coexist State[bitMap] change from 0x%"i64fmt"x to 0x%"i64fmt"x, changeBits = 0x%"i64fmt"x\n", + pHalData->bt_coexist.PreviousState, + pHalData->bt_coexist.CurrentState, + (pHalData->bt_coexist.PreviousState^pHalData->bt_coexist.CurrentState))); + pHalData->bt_coexist.PreviousState = pHalData->bt_coexist.CurrentState; + } +} + +u8 BTDM_IsSameCoexistState(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.PreviousState == pHalData->bt_coexist.CurrentState) { + return true; + } else { + RTPRINT(FBT, BT_TRACE, ("[DM][BT], Coexist state changed!!\n")); + return false; + } +} + +void BTDM_PWDBMonitor(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(GetDefaultAdapter(padapter)); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 H2C_Parameter[3] = {0}; + s32 tmpBTEntryMaxPWDB = 0, tmpBTEntryMinPWDB = 0xff; + u8 i; + + if (pBtMgnt->BtOperationOn) { + for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) { + if (pBTInfo->BtAsocEntry[i].bUsed) { + if (pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB < tmpBTEntryMinPWDB) + tmpBTEntryMinPWDB = pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB; + if (pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB > tmpBTEntryMaxPWDB) + tmpBTEntryMaxPWDB = pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB; + /* Report every BT connection (HS mode) RSSI to FW */ + H2C_Parameter[2] = (u8)(pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB & 0xFF); + H2C_Parameter[0] = (MAX_FW_SUPPORT_MACID_NUM-1-i); + RTPRINT(FDM, DM_BT30, ("RSSI report for BT[%d], H2C_Par = 0x%x\n", i, H2C_Parameter[0])); + FillH2CCmd(padapter, RSSI_SETTING_EID, 3, H2C_Parameter); + RTPRINT_ADDR(FDM, (DM_PWDB|DM_BT30), ("BT_Entry Mac :"), + pBTInfo->BtAsocEntry[i].BTRemoteMACAddr) + RTPRINT(FDM, (DM_PWDB|DM_BT30), + ("BT rx pwdb[%d] = 0x%x(%d)\n", i, + pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB, + pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB)); + } + } + if (tmpBTEntryMaxPWDB != 0) { /* If associated entry is found */ + pHalData->dmpriv.BT_EntryMaxUndecoratedSmoothedPWDB = tmpBTEntryMaxPWDB; + RTPRINT(FDM, (DM_PWDB|DM_BT30), ("BT_EntryMaxPWDB = 0x%x(%d)\n", + tmpBTEntryMaxPWDB, tmpBTEntryMaxPWDB)); + } else { + pHalData->dmpriv.BT_EntryMaxUndecoratedSmoothedPWDB = 0; + } + if (tmpBTEntryMinPWDB != 0xff) { /* If associated entry is found */ + pHalData->dmpriv.BT_EntryMinUndecoratedSmoothedPWDB = tmpBTEntryMinPWDB; + RTPRINT(FDM, (DM_PWDB|DM_BT30), ("BT_EntryMinPWDB = 0x%x(%d)\n", + tmpBTEntryMinPWDB, tmpBTEntryMinPWDB)); + } else { + pHalData->dmpriv.BT_EntryMinUndecoratedSmoothedPWDB = 0; + } + } +} + +u8 BTDM_IsBTBusy(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + + if (pBtMgnt->ExtConfig.bBTBusy) + return true; + else + return false; +} + +u8 BTDM_IsWifiBusy(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */ + struct mlme_priv *pmlmepriv = &GetDefaultAdapter(padapter)->mlmepriv; + struct bt_30info *pBTInfo = GET_BT_INFO(padapter); + struct bt_traffic *pBtTraffic = &pBTInfo->BtTraffic; + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic || + pBtTraffic->Bt30TrafficStatistics.bTxBusyTraffic || + pBtTraffic->Bt30TrafficStatistics.bRxBusyTraffic) + return true; + else + return false; +} + +u8 BTDM_IsCoexistStateChanged(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.PreviousState == pHalData->bt_coexist.CurrentState) + return false; + else + return true; +} + +u8 BTDM_IsWifiUplink(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */ + struct mlme_priv *pmlmepriv; + struct bt_30info *pBTInfo; + struct bt_traffic *pBtTraffic; + + pmlmepriv = &padapter->mlmepriv; + pBTInfo = GET_BT_INFO(padapter); + pBtTraffic = &pBTInfo->BtTraffic; + + if ((pmlmepriv->LinkDetectInfo.bTxBusyTraffic) || + (pBtTraffic->Bt30TrafficStatistics.bTxBusyTraffic)) + return true; + else + return false; +} + +u8 BTDM_IsWifiDownlink(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */ + struct mlme_priv *pmlmepriv; + struct bt_30info *pBTInfo; + struct bt_traffic *pBtTraffic; + + pmlmepriv = &padapter->mlmepriv; + pBTInfo = GET_BT_INFO(padapter); + pBtTraffic = &pBTInfo->BtTraffic; + + if ((pmlmepriv->LinkDetectInfo.bRxBusyTraffic) || + (pBtTraffic->Bt30TrafficStatistics.bRxBusyTraffic)) + return true; + else + return false; +} + +u8 BTDM_IsBTHSMode(struct rtw_adapter *padapter) +{ +/*PMGNT_INFO pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */ + struct hal_data_8723a *pHalData; + struct bt_mgnt *pBtMgnt; + + pHalData = GET_HAL_DATA(padapter); + pBtMgnt = &pHalData->BtInfo.BtMgnt; + + if (pBtMgnt->BtOperationOn) + return true; + else + return false; +} + +u8 BTDM_IsBTUplink(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic) + return true; + else + return false; +} + +u8 BTDM_IsBTDownlink(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic) + return true; + else + return false; +} + +void BTDM_AdjustForBtOperation(struct rtw_adapter *padapter) +{ + RTPRINT(FBT, BT_TRACE, ("[BT][DM], BTDM_AdjustForBtOperation()\n")); + BTDM_AdjustForBtOperation8723A(padapter); +} + +void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum) +{ + BTDM_Set8723ABtCoexCurrAntNum(padapter, antNum); +} + +void BTDM_ForHalt(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + BTDM_ForHalt8723A(padapter); + GET_HAL_DATA(padapter)->bt_coexist.bInitlized = false; +} + +void BTDM_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + BTDM_WifiScanNotify8723A(padapter, scanType); +} + +void BTDM_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + BTDM_WifiAssociateNotify8723A(padapter, action); +} + +void BTDM_MediaStatusNotify(struct rtw_adapter *padapter, enum rt_media_status mstatus) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + BTDM_MediaStatusNotify8723A(padapter, mstatus); +} + +void BTDM_ForDhcp(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!pHalData->bt_coexist.BluetoothCoexist) + return; + + BTDM_ForDhcp8723A(padapter); +} + +void BTDM_ResetActionProfileState(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + pHalData->bt_coexist.CurrentState &= ~\ + (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP| + BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_SCO); +} + +u8 BTDM_IsActionSCO(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_SCO) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_SCO; + bRet = true; + } + } else { + if (pBtMgnt->ExtConfig.NumberOfSCO > 0) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_SCO; + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionHID(struct rtw_adapter *padapter) +{ + struct bt_30info *pBTInfo; + struct hal_data_8723a *pHalData; + struct bt_mgnt *pBtMgnt; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_HID; + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + pBtMgnt->ExtConfig.NumberOfHandle == 1) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_HID; + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionA2DP(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_A2DP) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_A2DP; + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP) && + pBtMgnt->ExtConfig.NumberOfHandle == 1) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_A2DP; + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionPAN(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_PAN) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_PAN; + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && + pBtMgnt->ExtConfig.NumberOfHandle == 1) { + pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_PAN; + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionHIDA2DP(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_mgnt *pBtMgnt; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtMgnt = &pBTInfo->BtMgnt; + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID_A2DP) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP); + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP); + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionHIDPAN(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID_PAN) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_PAN); + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) && + BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_PAN); + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsActionPANA2DP(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct bt_30info *pBTInfo; + struct bt_dgb *pBtDbg; + u8 bRet; + + pHalData = GET_HAL_DATA(padapter); + pBTInfo = GET_BT_INFO(padapter); + pBtDbg = &pBTInfo->BtDbg; + bRet = false; + + if (pBtDbg->dbgCtrl) { + if (pBtDbg->dbgProfile == BT_DBG_PROFILE_PAN_A2DP) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_A2DP); + bRet = true; + } + } else { + if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) { + pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_A2DP); + bRet = true; + } + } + return bRet; +} + +u8 BTDM_IsBtDisabled(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.bCurBtDisabled) + return true; + else + return false; +} + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.c ===== */ +#endif + +#ifdef __HALBT_C__ /* HAL/HalBT.c */ +/* ===== Below this line is sync from SD7 driver HAL/HalBT.c ===== */ + +/* */ +/*local function */ +/* */ + +static void halbt_InitHwConfig8723A(struct rtw_adapter *padapter) +{ +} + +/* */ +/*extern function */ +/* */ +u8 HALBT_GetPGAntNum(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + return pHalData->bt_coexist.BT_Ant_Num; +} + +void HALBT_SetKey(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTinfo; + struct bt_asoc_entry *pBtAssocEntry; + u16 usConfig = 0; + + pBTinfo = GET_BT_INFO(padapter); + pBtAssocEntry = &pBTinfo->BtAsocEntry[EntryNum]; + + pBtAssocEntry->HwCAMIndex = BT_HWCAM_STAR + EntryNum; + + usConfig = CAM_VALID | (CAM_AES << 2); + write_cam23a(padapter, pBtAssocEntry->HwCAMIndex, usConfig, pBtAssocEntry->BTRemoteMACAddr, pBtAssocEntry->PTK + TKIP_ENC_KEY_POS); +} + +void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum) +{ + struct bt_30info *pBTinfo; + struct bt_asoc_entry *pBtAssocEntry; + + pBTinfo = GET_BT_INFO(padapter); + pBtAssocEntry = &pBTinfo->BtAsocEntry[EntryNum]; + + if (pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex != 0) { + /* ToDo : add New HALBT_RemoveKey function !! */ + if (pBtAssocEntry->HwCAMIndex >= BT_HWCAM_STAR && pBtAssocEntry->HwCAMIndex < HALF_CAM_ENTRY) + CAM_empty_entry23a(padapter, pBtAssocEntry->HwCAMIndex); + pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex = 0; + } +} + +void HALBT_InitBTVars8723A(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + + pHalData = GET_HAL_DATA(padapter); + + pHalData->bt_coexist.BluetoothCoexist = pHalData->EEPROMBluetoothCoexist; + pHalData->bt_coexist.BT_Ant_Num = pHalData->EEPROMBluetoothAntNum; + pHalData->bt_coexist.BT_CoexistType = pHalData->EEPROMBluetoothType; + pHalData->bt_coexist.BT_Ant_isolation = pHalData->EEPROMBluetoothAntIsolation; + pHalData->bt_coexist.bt_radiosharedtype = pHalData->EEPROMBluetoothRadioShared; + + RT_TRACE(_module_hal_init_c_, _drv_info_, ("BT Coexistance = 0x%x\n", pHalData->bt_coexist.BluetoothCoexist)); + if (pHalData->bt_coexist.BluetoothCoexist) { + if (pHalData->bt_coexist.BT_Ant_Num == Ant_x2) { + BTDM_SetBtCoexCurrAntNum(padapter, 2); + RT_TRACE(_module_hal_init_c_, _drv_info_, ("BlueTooth BT_Ant_Num = Antx2\n")); + } else if (pHalData->bt_coexist.BT_Ant_Num == Ant_x1) { + BTDM_SetBtCoexCurrAntNum(padapter, 1); + RT_TRACE(_module_hal_init_c_, _drv_info_, ("BlueTooth BT_Ant_Num = Antx1\n")); + } + pHalData->bt_coexist.bBTBusyTraffic = false; + pHalData->bt_coexist.bBTTrafficModeSet = false; + pHalData->bt_coexist.bBTNonTrafficModeSet = false; + pHalData->bt_coexist.CurrentState = 0; + pHalData->bt_coexist.PreviousState = 0; + + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("bt_radiosharedType = 0x%x\n", + pHalData->bt_coexist.bt_radiosharedtype)); + } +} + +u8 HALBT_IsBTExist(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->bt_coexist.BluetoothCoexist) + return true; + else + return false; +} + +u8 HALBT_BTChipType(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + return pHalData->bt_coexist.BT_CoexistType; +} + +void HALBT_InitHwConfig(struct rtw_adapter *padapter) +{ + halbt_InitHwConfig8723A(padapter); + BTDM_Coexist(padapter); +} + +void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter *padapter) +{ +} + +/* ===== End of sync from SD7 driver HAL/HalBT.c ===== */ +#endif diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c b/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c new file mode 100644 index 000000000000..0b205e1204fc --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c @@ -0,0 +1,845 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8723A_CMD_C_ + +#include +#include +#include +#include +#include +#include +#include + +#define RTL92C_MAX_H2C_BOX_NUMS 4 +#define RTL92C_MAX_CMD_LEN 5 +#define MESSAGE_BOX_SIZE 4 +#define EX_MESSAGE_BOX_SIZE 2 + +static u8 _is_fw_read_cmd_down(struct rtw_adapter *padapter, u8 msgbox_num) +{ + u8 read_down = false; + int retry_cnts = 100; + u8 valid; + + do { + valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num); + if (0 == valid) + read_down = true; + } while ((!read_down) && (retry_cnts--)); + + return read_down; +} + +/***************************************** +* H2C Msg format : +*| 31 - 8 |7 | 6 - 0 | +*| h2c_msg |Ext_bit |CMD_ID | +* +******************************************/ +s32 FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) +{ + u8 bcmd_down = false; + s32 retry_cnts = 100; + u8 h2c_box_num; + u32 msgbox_addr; + u32 msgbox_ex_addr; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 h2c_cmd = 0; + u16 h2c_cmd_ex = 0; + s32 ret = _FAIL; + + padapter = GET_PRIMARY_ADAPTER(padapter); + pHalData = GET_HAL_DATA(padapter); + + mutex_lock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex); + + if (!pCmdBuffer) + goto exit; + if (CmdLen > RTL92C_MAX_CMD_LEN) + goto exit; + if (padapter->bSurpriseRemoved == true) + goto exit; + + /* pay attention to if race condition happened in H2C cmd setting. */ + do { + h2c_box_num = pHalData->LastHMEBoxNum; + + if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) { + DBG_8723A(" fw read cmd failed...\n"); + goto exit; + } + + if (CmdLen <= 3) { + memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); + } else { + memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer, EX_MESSAGE_BOX_SIZE); + memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer+2, (CmdLen-EX_MESSAGE_BOX_SIZE)); + *(u8 *)(&h2c_cmd) |= BIT(7); + } + + *(u8 *)(&h2c_cmd) |= ElementID; + + if (h2c_cmd & BIT(7)) { + msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE); + h2c_cmd_ex = le16_to_cpu(h2c_cmd_ex); + rtw_write16(padapter, msgbox_ex_addr, h2c_cmd_ex); + } + msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * MESSAGE_BOX_SIZE); + h2c_cmd = le32_to_cpu(h2c_cmd); + rtw_write32(padapter, msgbox_addr, h2c_cmd); + + bcmd_down = true; + + pHalData->LastHMEBoxNum = (h2c_box_num+1) % RTL92C_MAX_H2C_BOX_NUMS; + + } while ((!bcmd_down) && (retry_cnts--)); + + ret = _SUCCESS; + +exit: + mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex); + return ret; +} + +u8 rtl8723a_set_rssi_cmd(struct rtw_adapter *padapter, u8 *param) +{ + u8 res = _SUCCESS; + + *((u32 *)param) = cpu_to_le32(*((u32 *)param)); + + FillH2CCmd(padapter, RSSI_SETTING_EID, 3, param); + + return res; +} + +u8 rtl8723a_set_raid_cmd(struct rtw_adapter *padapter, u32 mask, u8 arg) +{ + u8 buf[5]; + u8 res = _SUCCESS; + + memset(buf, 0, 5); + mask = cpu_to_le32(mask); + memcpy(buf, &mask, 4); + buf[4] = arg; + + FillH2CCmd(padapter, MACID_CONFIG_EID, 5, buf); + + return res; + +} + +/* bitmap[0:27] = tx_rate_bitmap */ +/* bitmap[28:31]= Rate Adaptive id */ +/* arg[0:4] = macid */ +/* arg[5] = Short GI */ +void rtl8723a_add_rateatid(struct rtw_adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + u8 macid = arg&0x1f; + u8 raid = (bitmap>>28) & 0x0f; + + bitmap &= 0x0fffffff; + if (rssi_level != DM_RATR_STA_INIT) + bitmap = ODM_Get_Rate_Bitmap23a(&pHalData->odmpriv, macid, bitmap, rssi_level); + + bitmap |= ((raid<<28)&0xf0000000); + + if (pHalData->fw_ractrl == true) { + rtl8723a_set_raid_cmd(pAdapter, bitmap, arg); + } else { + u8 init_rate, shortGIrate = false; + + init_rate = get_highest_rate_idx23a(bitmap&0x0fffffff)&0x3f; + + shortGIrate = (arg&BIT(5)) ? true:false; + + if (shortGIrate == true) + init_rate |= BIT(6); + + rtw_write8(pAdapter, (REG_INIDATA_RATE_SEL+macid), (u8)init_rate); + } +} + +void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode) +{ + struct setpwrmode_parm H2CSetPwrMode; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + DBG_8723A("%s: Mode =%d SmartPS =%d UAPSD =%d BcnMode = 0x%02x\n", __FUNCTION__, + Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable, pwrpriv->bcn_ant_mode); + + /* Forece leave RF low power mode for 1T1R to + prevent conficting setting in Fw power */ + /* saving sequence. 2010.06.07. Added by tynli. + Suggested by SD3 yschang. */ + if ((Mode != PS_MODE_ACTIVE) && + (!IS_92C_SERIAL(pHalData->VersionID))) { + ODM_RF_Saving23a(&pHalData->odmpriv, true); + } + + H2CSetPwrMode.Mode = Mode; + H2CSetPwrMode.SmartPS = pwrpriv->smart_ps; + H2CSetPwrMode.AwakeInterval = 1; + H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable; + H2CSetPwrMode.BcnAntMode = pwrpriv->bcn_ant_mode; + + FillH2CCmd(padapter, SET_PWRMODE_EID, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode); + +} + +static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength) +{ + struct ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 rate_len, pktlen; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + /* DBG_8723A("%s\n", __FUNCTION__); */ + + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + + memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, get_my_bssid23a(cur_network), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + SetFrameSubType(pframe, WIFI_BEACON); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pktlen = sizeof (struct ieee80211_hdr_3addr); + + /* timestamp will be inserted by hardware */ + pframe += 8; + pktlen += 8; + + /* beacon interval: 2 bytes */ + memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval23a_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + /* capability info: 2 bytes */ + memcpy(pframe, (unsigned char *)(rtw_get_capability23a_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { + /* DBG_8723A("ie len =%d\n", cur_network->IELength); */ + pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ies); + memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ies), pktlen); + + goto _ConstructBeacon; + } + + /* below for ad-hoc mode */ + + /* SSID */ + pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len, + cur_network->Ssid.ssid, &pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates); + pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? + 8 : rate_len), cur_network->SupportedRates, &pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pktlen); + + if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); + } + + /* todo: ERP IE */ + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); + + /* todo:HT for adhoc */ + +_ConstructBeacon: + + if ((pktlen + TXDESC_SIZE) > 512) { + DBG_8723A("beacon frame too large\n"); + return; + } + + *pLength = pktlen; + + /* DBG_8723A("%s bcn_sz =%d\n", __FUNCTION__, pktlen); */ + +} + +static void ConstructPSPoll(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength) +{ + struct ieee80211_hdr *pwlanhdr; + u16 *fctrl; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + pwlanhdr = (struct ieee80211_hdr *)pframe; + + /* Frame control. */ + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + SetPwrMgt(fctrl); + SetFrameSubType(pframe, WIFI_PSPOLL); + + /* AID. */ + SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); + + /* BSSID. */ + memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); + + /* TA. */ + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + + *pLength = 16; +} + +static void ConstructNullFunctionData( + struct rtw_adapter *padapter, + u8 *pframe, + u32 *pLength, + u8 *StaAddr, + u8 bQoS, + u8 AC, + u8 bEosp, + u8 bForcePowerSave) +{ + struct ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + pwlanhdr = (struct ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + if (bForcePowerSave) + SetPwrMgt(fctrl); + + switch (cur_network->network.InfrastructureMode) { + case Ndis802_11Infrastructure: + SetToDs(fctrl); + memcpy(pwlanhdr->addr1, + get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), + ETH_ALEN); + memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); + break; + case Ndis802_11APMode: + SetFrDs(fctrl); + memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + memcpy(pwlanhdr->addr2, + get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); + memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), + ETH_ALEN); + break; + case Ndis802_11IBSS: + default: + memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, + get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); + break; + } + + SetSeqNum(pwlanhdr, 0); + + if (bQoS == true) { + struct ieee80211_qos_hdr *pwlanqoshdr; + + SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); + + pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe; + SetPriority(&pwlanqoshdr->qos_ctrl, AC); + SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp); + + pktlen = sizeof(struct ieee80211_qos_hdr); + } else { + SetFrameSubType(pframe, WIFI_DATA_NULL); + + pktlen = sizeof(struct ieee80211_hdr_3addr); + } + + *pLength = pktlen; +} + +static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) +{ + struct ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u8 *mac, *bssid; + u32 pktlen; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + + /* DBG_8723A("%s\n", __FUNCTION__); */ + + pwlanhdr = (struct ieee80211_hdr *)pframe; + + mac = myid(&padapter->eeprompriv); + bssid = cur_network->MacAddress; + + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + SetFrameSubType(fctrl, WIFI_PROBERSP); + + pktlen = sizeof(struct ieee80211_hdr_3addr); + pframe += pktlen; + + if (cur_network->IELength > MAX_IE_SZ) + return; + + memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pktlen += cur_network->IELength; + + *pLength = pktlen; +} + +/* To check if reserved page content is destroyed by beacon beacuse beacon is too large. */ +void CheckFwRsvdPageContent23a(struct rtw_adapter *Adapter) +{ +} + +/* */ +/* Description: Fill the reserved packets that FW will use to RSVD page. */ +/* Now we just send 4 types packet to rsvd page. */ +/* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */ +/* Input: */ +/* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */ +/* so we need to set the packet length to total lengh. */ +/* true: At the second time, we should send the first packet (default:beacon) */ +/* to Hw again and set the lengh in descriptor to the real beacon lengh. */ +/* 2009.10.15 by tynli. */ +static void SetFwRsvdPagePkt(struct rtw_adapter *padapter, bool bDLFinished) +{ + struct hal_data_8723a *pHalData; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength; + u32 NullDataLength, QosNullLength, BTQosNullLength; + u8 *ReservedPagePacket; + u8 PageNum, PageNeed, TxDescLen; + u16 BufIndex; + u32 TotalPacketLen; + struct rsvdpage_loc RsvdPageLoc; + + DBG_8723A("%s\n", __FUNCTION__); + + ReservedPagePacket = kzalloc(1000, GFP_KERNEL); + if (ReservedPagePacket == NULL) { + DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); + return; + } + + pHalData = GET_HAL_DATA(padapter); + pxmitpriv = &padapter->xmitpriv; + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + TxDescLen = TXDESC_SIZE; + PageNum = 0; + + /* 3 (1) beacon */ + BufIndex = TXDESC_OFFSET; + ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength); + + /* When we count the first page size, we need to reserve description size for the RSVD */ + /* packet, it will be filled in front of the packet in TXPKTBUF. */ + PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength); + /* To reserved 2 pages for beacon buffer. 2010.06.24. */ + if (PageNeed == 1) + PageNeed += 1; + PageNum += PageNeed; + pHalData->FwRsvdPageStartOffset = PageNum; + + BufIndex += PageNeed*128; + + /* 3 (2) ps-poll */ + RsvdPageLoc.LocPsPoll = PageNum; + ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false); + + PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength); + PageNum += PageNeed; + + BufIndex += PageNeed*128; + + /* 3 (3) null data */ + RsvdPageLoc.LocNullData = PageNum; + ConstructNullFunctionData( + padapter, + &ReservedPagePacket[BufIndex], + &NullDataLength, + get_my_bssid23a(&pmlmeinfo->network), + false, 0, 0, false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false); + + PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength); + PageNum += PageNeed; + + BufIndex += PageNeed*128; + + /* 3 (4) probe response */ + RsvdPageLoc.LocProbeRsp = PageNum; + ConstructProbeRsp( + padapter, + &ReservedPagePacket[BufIndex], + &ProbeRspLength, + get_my_bssid23a(&pmlmeinfo->network), + false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false); + + PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength); + PageNum += PageNeed; + + BufIndex += PageNeed*128; + + /* 3 (5) Qos null data */ + RsvdPageLoc.LocQosNull = PageNum; + ConstructNullFunctionData( + padapter, + &ReservedPagePacket[BufIndex], + &QosNullLength, + get_my_bssid23a(&pmlmeinfo->network), + true, 0, 0, false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false); + + PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength); + PageNum += PageNeed; + + BufIndex += PageNeed*128; + + /* 3 (6) BT Qos null data */ + RsvdPageLoc.LocBTQosNull = PageNum; + ConstructNullFunctionData( + padapter, + &ReservedPagePacket[BufIndex], + &BTQosNullLength, + get_my_bssid23a(&pmlmeinfo->network), + true, 0, 0, false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true); + + TotalPacketLen = BufIndex + BTQosNullLength; + + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->qsel = 0x10; + pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET; + memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen); + + rtw_hal_mgnt_xmit23a(padapter, pmgntframe); + + DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__); + FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc); + +exit: + kfree(ReservedPagePacket); +} + +void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter *padapter, u8 mstatus) +{ + struct joinbssrpt_parm JoinBssRptParm; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + DBG_8723A("%s mstatus(%x)\n", __FUNCTION__, mstatus); + + if (mstatus == 1) { + bool bRecover = false; + u8 v8; + + /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ + /* Suggested by filen. Added by tynli. */ + rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); + /* Do not set TSF again here or vWiFi beacon DMA INT will not work. */ + /* correct_TSF23a(padapter, pmlmeext); */ + /* Hw sequende enable by dedault. 2010.06.23. by tynli. */ + /* rtw_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); */ + /* rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); */ + + /* set REG_CR bit 8 */ + v8 = rtw_read8(padapter, REG_CR+1); + v8 |= BIT(0); /* ENSWBCN */ + rtw_write8(padapter, REG_CR+1, v8); + + /* Disable Hw protection for a time which revserd for Hw sending beacon. */ + /* Fix download reserved page packet fail that access collision with the protection time. */ + /* 2010.05.11. Added by tynli. */ +/* SetBcnCtrlReg23a(padapter, 0, BIT(3)); */ +/* SetBcnCtrlReg23a(padapter, BIT(4), 0); */ + SetBcnCtrlReg23a(padapter, BIT(4), BIT(3)); + + /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ + if (pHalData->RegFwHwTxQCtrl & BIT(6)) + bRecover = true; + + /* To tell Hw the packet is not a real beacon frame. */ + /* U1bTmp = rtw_read8(padapter, REG_FWHW_TXQ_CTRL+2); */ + rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6)); + pHalData->RegFwHwTxQCtrl &= ~BIT(6); + SetFwRsvdPagePkt(padapter, 0); + + /* 2010.05.11. Added by tynli. */ + SetBcnCtrlReg23a(padapter, BIT(3), BIT(4)); + + /* To make sure that if there exists an adapter which would like to send beacon. */ + /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ + /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ + /* the beacon cannot be sent by HW. */ + /* 2010.06.23. Added by tynli. */ + if (bRecover) { + rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6)); + pHalData->RegFwHwTxQCtrl |= BIT(6); + } + + /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ + v8 = rtw_read8(padapter, REG_CR+1); + v8 &= ~BIT(0); /* ~ENSWBCN */ + rtw_write8(padapter, REG_CR+1, v8); + } + + JoinBssRptParm.OpMode = mstatus; + + FillH2CCmd(padapter, JOINBSS_RPT_EID, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm); + +} + +#ifdef CONFIG_8723AU_BT_COEXIST +static void SetFwRsvdPagePkt_BTCoex(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + u8 fakemac[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x00}; + u32 NullDataLength, BTQosNullLength; + u8 *ReservedPagePacket; + u8 PageNum, PageNeed, TxDescLen; + u16 BufIndex; + u32 TotalPacketLen; + struct rsvdpage_loc RsvdPageLoc; + + DBG_8723A("+%s\n", __FUNCTION__); + + ReservedPagePacket = kzalloc(1024, GFP_KERNEL); + if (ReservedPagePacket == NULL) { + DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); + return; + } + + pHalData = GET_HAL_DATA(padapter); + pxmitpriv = &padapter->xmitpriv; + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + TxDescLen = TXDESC_SIZE; + PageNum = 0; + + /* 3 (1) beacon */ + BufIndex = TXDESC_OFFSET; + /* skip Beacon Packet */ + PageNeed = 3; + + PageNum += PageNeed; + pHalData->FwRsvdPageStartOffset = PageNum; + + BufIndex += PageNeed*128; + + /* 3 (3) null data */ + RsvdPageLoc.LocNullData = PageNum; + ConstructNullFunctionData( + padapter, + &ReservedPagePacket[BufIndex], + &NullDataLength, + fakemac, + false, 0, 0, false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false); + + PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength); + PageNum += PageNeed; + + BufIndex += PageNeed*128; + + /* 3 (6) BT Qos null data */ + RsvdPageLoc.LocBTQosNull = PageNum; + ConstructNullFunctionData( + padapter, + &ReservedPagePacket[BufIndex], + &BTQosNullLength, + fakemac, + true, 0, 0, false); + rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true); + + TotalPacketLen = BufIndex + BTQosNullLength; + + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->qsel = 0x10; + pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET; + memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen); + + rtw_hal_mgnt_xmit23a(padapter, pmgntframe); + + DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__); + FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc); + +exit: + kfree(ReservedPagePacket); +} + +void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + u8 bRecover = false; + + DBG_8723A("+%s\n", __FUNCTION__); + + pHalData = GET_HAL_DATA(padapter); + + /* Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */ + if (pHalData->RegFwHwTxQCtrl & BIT(6)) + bRecover = true; + + /* To tell Hw the packet is not a real beacon frame. */ + pHalData->RegFwHwTxQCtrl &= ~BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); + SetFwRsvdPagePkt_BTCoex(padapter); + + /* To make sure that if there exists an adapter which would like to send beacon. */ + /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ + /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ + /* the beacon cannot be sent by HW. */ + /* 2010.06.23. Added by tynli. */ + if (bRecover) { + pHalData->RegFwHwTxQCtrl |= BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl); + } +} +#endif + +#ifdef CONFIG_8723AU_P2P +void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter *padapter, u8 p2p_ps_state) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload; + u8 i; + + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + DBG_8723A("P2P_PS_DISABLE \n"); + memset(p2p_ps_offload, 0, 1); + break; + case P2P_PS_ENABLE: + DBG_8723A("P2P_PS_ENABLE \n"); + /* update CTWindow value. */ + if (pwdinfo->ctwindow > 0) { + p2p_ps_offload->CTWindow_En = 1; + rtw_write8(padapter, REG_P2P_CTWIN, pwdinfo->ctwindow); + } + + /* hw only support 2 set of NoA */ + for (i = 0; i < pwdinfo->noa_num; i++) { + /* To control the register setting for which NOA */ + rtw_write8(padapter, REG_NOA_DESC_SEL, (i << 4)); + if (i == 0) + p2p_ps_offload->NoA0_En = 1; + else + p2p_ps_offload->NoA1_En = 1; + + /* config P2P NoA Descriptor Register */ + rtw_write32(padapter, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]); + + rtw_write32(padapter, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]); + + rtw_write32(padapter, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]); + + rtw_write8(padapter, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]); + } + + if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) { + /* rst p2p circuit */ + rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4)); + + p2p_ps_offload->Offload_En = 1; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + p2p_ps_offload->role = 1; + p2p_ps_offload->AllStaSleep = 0; + } else { + p2p_ps_offload->role = 0; + } + + p2p_ps_offload->discovery = 0; + } + break; + case P2P_PS_SCAN: + DBG_8723A("P2P_PS_SCAN \n"); + p2p_ps_offload->discovery = 1; + break; + case P2P_PS_SCAN_DONE: + DBG_8723A("P2P_PS_SCAN_DONE \n"); + p2p_ps_offload->discovery = 0; + pwdinfo->p2p_ps_state = P2P_PS_ENABLE; + break; + default: + break; + } + + FillH2CCmd(padapter, P2P_PS_OFFLOAD_EID, 1, (u8 *)p2p_ps_offload); +} +#endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_dm.c b/drivers/staging/rtl8723au/hal/rtl8723a_dm.c new file mode 100644 index 000000000000..f204ab1714e7 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_dm.c @@ -0,0 +1,273 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/* */ +/* Description: */ +/* */ +/* This file is for 92CE/92CU dynamic mechanism only */ +/* */ +/* */ +/* */ +#define _RTL8723A_DM_C_ + +/* */ +/* include files */ +/* */ +#include +#include + +#include + +/* */ +/* Global var */ +/* */ + +static void dm_CheckStatistics(struct rtw_adapter *Adapter) +{ +} + +static void dm_CheckPbcGPIO(struct rtw_adapter *padapter) +{ + u8 tmp1byte; + u8 bPbcPressed = false; + + if (!padapter->registrypriv.hw_wps_pbc) + return; + + tmp1byte = rtw_read8(padapter, GPIO_IO_SEL); + tmp1byte |= (HAL_8192C_HW_GPIO_WPS_BIT); + rtw_write8(padapter, GPIO_IO_SEL, tmp1byte); /* enable GPIO[2] as output mode */ + + tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT); + rtw_write8(padapter, GPIO_IN, tmp1byte); /* reset the floating voltage level */ + + tmp1byte = rtw_read8(padapter, GPIO_IO_SEL); + tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT); + rtw_write8(padapter, GPIO_IO_SEL, tmp1byte); /* enable GPIO[2] as input mode */ + + tmp1byte = rtw_read8(padapter, GPIO_IN); + + if (tmp1byte == 0xff) + return; + + if (tmp1byte&HAL_8192C_HW_GPIO_WPS_BIT) + bPbcPressed = true; + + if (bPbcPressed) { + /* Here we only set bPbcPressed to true */ + /* After trigger PBC, the variable will be set to false */ + DBG_8723A("CheckPbcGPIO - PBC is pressed\n"); + + if (padapter->pid[0] == 0) { + /* 0 is the default value and it means the application + * monitors the HW PBC doesn't privde its pid to driver. + */ + return; + } + + rtw_signal_process(padapter->pid[0], SIGUSR1); + } +} + +/* Initialize GPIO setting registers */ +/* functions */ +static void Init_ODM_ComInfo_8723a(struct rtw_adapter *Adapter) +{ + + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + u8 cut_ver, fab_ver; + + /* */ + /* Init Value */ + /* */ + memset(pDM_Odm, 0, sizeof(*pDM_Odm)); + + pDM_Odm->Adapter = Adapter; + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_PLATFORM, 0x04); + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_INTERFACE, RTW_USB);/* RTL871X_HCI_TYPE */ + + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8723A); + + if (IS_8723A_A_CUT(pHalData->VersionID)) { + fab_ver = ODM_UMC; + cut_ver = ODM_CUT_A; + } else if (IS_8723A_B_CUT(pHalData->VersionID)) { + fab_ver = ODM_UMC; + cut_ver = ODM_CUT_B; + } else { + fab_ver = ODM_TSMC; + cut_ver = ODM_CUT_A; + } + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_FAB_VER, fab_ver); + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_CUT_VER, cut_ver); + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(pHalData->VersionID)); + + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_BOARD_TYPE, pHalData->BoardType); + + if (pHalData->BoardType == BOARD_USB_High_PA) { + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_EXT_LNA, true); + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_EXT_PA, true); + } + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_PATCH_ID, pHalData->CustomerID); + ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec); + + if (pHalData->rf_type == RF_1T1R) + ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); + else if (pHalData->rf_type == RF_2T2R) + ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); + else if (pHalData->rf_type == RF_1T2R) + ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); +} + +static void Update_ODM_ComInfo_8723a(struct rtw_adapter *Adapter) +{ + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + struct dm_priv *pdmpriv = &pHalData->dmpriv; + int i; + pdmpriv->InitODMFlag = ODM_BB_DIG | + ODM_BB_RA_MASK | + ODM_BB_DYNAMIC_TXPWR | + ODM_BB_FA_CNT | + ODM_BB_RSSI_MONITOR | + ODM_BB_CCK_PD | + ODM_BB_PWR_SAVE | + ODM_MAC_EDCA_TURBO | + ODM_RF_TX_PWR_TRACK | + ODM_RF_CALIBRATION; + /* Pointer reference */ + + ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); + + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_TX_UNI, + &Adapter->xmitpriv.tx_bytes); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_RX_UNI, + &Adapter->recvpriv.rx_bytes); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_WM_MODE, + &pmlmeext->cur_wireless_mode); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_CHNL_OFFSET, + &pHalData->nCur40MhzPrimeSC); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_MODE, + &Adapter->securitypriv.dot11PrivacyAlgrthm); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_BW, + &pHalData->CurrentChannelBW); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_CHNL, + &pHalData->CurrentChannel); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_NET_CLOSED, &Adapter->net_closed); + + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SCAN, &pmlmepriv->bScanInProcess); + ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_POWER_SAVING, + &pwrctrlpriv->bpower_saving); + + for (i = 0; i < NUM_STA; i++) + ODM_CmnInfoPtrArrayHook23a(pDM_Odm, ODM_CMNINFO_STA_STATUS, i, NULL); +} + +void rtl8723a_InitHalDm(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + u8 i; + + pdmpriv->DM_Type = DM_Type_ByDriver; + pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; + +#ifdef CONFIG_8723AU_BT_COEXIST + pdmpriv->DMFlag |= DYNAMIC_FUNC_BT; +#endif + pdmpriv->InitDMFlag = pdmpriv->DMFlag; + + Update_ODM_ComInfo_8723a(Adapter); + ODM23a_DMInit(pDM_Odm); + /* Save REG_INIDATA_RATE_SEL value for TXDESC. */ + for (i = 0; i < 32; i++) + pdmpriv->INIDATA_RATE[i] = rtw_read8(Adapter, REG_INIDATA_RATE_SEL+i) & 0x3f; +} + +void +rtl8723a_HalDmWatchDog( + struct rtw_adapter *Adapter + ) +{ + bool bFwCurrentInPSMode = false; + bool bFwPSAwake = true; + u8 hw_init_completed = false; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + + hw_init_completed = Adapter->hw_init_completed; + + if (hw_init_completed == false) + goto skip_dm; + + bFwCurrentInPSMode = Adapter->pwrctrlpriv.bFwCurrentInPSMode; + rtw23a_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake)); + +#ifdef CONFIG_8723AU_P2P + /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */ + /* modifed by thomas. 2011.06.11. */ + if (Adapter->wdinfo.p2p_ps_mode) + bFwPSAwake = false; +#endif /* CONFIG_8723AU_P2P */ + + if ((hw_init_completed) && ((!bFwCurrentInPSMode) && bFwPSAwake)) { + /* Calculate Tx/Rx statistics. */ + dm_CheckStatistics(Adapter); + + /* Read REG_INIDATA_RATE_SEL value for TXDESC. */ + if (check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE)) { + pdmpriv->INIDATA_RATE[0] = rtw_read8(Adapter, REG_INIDATA_RATE_SEL) & 0x3f; + } else { + u8 i; + for (i = 1 ; i < (Adapter->stapriv.asoc_sta_count + 1); i++) + pdmpriv->INIDATA_RATE[i] = rtw_read8(Adapter, (REG_INIDATA_RATE_SEL+i)) & 0x3f; + } + } + + /* ODM */ + if (hw_init_completed == true) { + u8 bLinked = false; + + if (rtw_linked_check(Adapter)) + bLinked = true; + + ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_LINK, + bLinked); + ODM_DMWatchdog23a(&pHalData->odmpriv); + } + +skip_dm: + + /* Check GPIO to determine current RF on/off and Pbc status. */ + /* Check Hardware Radio ON/OFF or not */ + dm_CheckPbcGPIO(Adapter); +} + +void rtl8723a_init_dm_priv(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + + memset(pdmpriv, 0, sizeof(struct dm_priv)); + Init_ODM_ComInfo_8723a(Adapter); +} + +void rtl8723a_deinit_dm_priv(struct rtw_adapter *Adapter) +{ +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c new file mode 100644 index 000000000000..fd00ddb3c951 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -0,0 +1,3452 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _HAL_INIT_C_ + +#include +#include +#include + +#include + +static void _FWDownloadEnable(struct rtw_adapter *padapter, bool enable) +{ + u8 tmp; + + if (enable) { + /* 8051 enable */ + tmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); + rtw_write8(padapter, REG_SYS_FUNC_EN + 1, tmp | 0x04); + + /* MCU firmware download enable. */ + tmp = rtw_read8(padapter, REG_MCUFWDL); + rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01); + + /* 8051 reset */ + tmp = rtw_read8(padapter, REG_MCUFWDL + 2); + rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7); + } else { + /* MCU firmware download disable. */ + tmp = rtw_read8(padapter, REG_MCUFWDL); + rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe); + + /* Reserved for fw extension. */ + rtw_write8(padapter, REG_MCUFWDL + 1, 0x00); + } +} + +static int _BlockWrite(struct rtw_adapter *padapter, void *buffer, u32 buffSize) +{ + int ret = _SUCCESS; + /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ + u32 blockSize_p1 = 4; + /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ + u32 blockSize_p2 = 8; + /* Phase #3 : Use 1-byte, the remnant of FW image. */ + u32 blockSize_p3 = 1; + u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; + u32 remainSize_p1 = 0, remainSize_p2 = 0; + u8 *bufferPtr = (u8 *) buffer; + u32 i = 0, offset = 0; + + blockSize_p1 = 254; + + /* 3 Phase #1 */ + blockCount_p1 = buffSize / blockSize_p1; + remainSize_p1 = buffSize % blockSize_p1; + + if (blockCount_p1) { + RT_TRACE(_module_hal_init_c_, _drv_notice_, + ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) " + "blockCount_p1(%d) remainSize_p1(%d)\n", + buffSize, blockSize_p1, blockCount_p1, + remainSize_p1)); + } + + for (i = 0; i < blockCount_p1; i++) { + ret = rtw_writeN(padapter, + (FW_8723A_START_ADDRESS + i * blockSize_p1), + blockSize_p1, (bufferPtr + i * blockSize_p1)); + if (ret == _FAIL) + goto exit; + } + + /* 3 Phase #2 */ + if (remainSize_p1) { + offset = blockCount_p1 * blockSize_p1; + + blockCount_p2 = remainSize_p1 / blockSize_p2; + remainSize_p2 = remainSize_p1 % blockSize_p2; + + if (blockCount_p2) { + RT_TRACE(_module_hal_init_c_, _drv_notice_, + ("_BlockWrite: [P2] buffSize_p2(%d) " + "blockSize_p2(%d) blockCount_p2(%d) " + "remainSize_p2(%d)\n", + (buffSize - offset), blockSize_p2, + blockCount_p2, remainSize_p2)); + } + + for (i = 0; i < blockCount_p2; i++) { + ret = rtw_writeN(padapter, + (FW_8723A_START_ADDRESS + offset + + i * blockSize_p2), blockSize_p2, + (bufferPtr + offset + + i * blockSize_p2)); + + if (ret == _FAIL) + goto exit; + } + } + + /* 3 Phase #3 */ + if (remainSize_p2) { + offset = (blockCount_p1 * blockSize_p1) + + (blockCount_p2 * blockSize_p2); + + blockCount_p3 = remainSize_p2 / blockSize_p3; + + RT_TRACE(_module_hal_init_c_, _drv_notice_, + ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) " + "blockCount_p3(%d)\n", + (buffSize - offset), blockSize_p3, blockCount_p3)); + + for (i = 0; i < blockCount_p3; i++) { + ret = rtw_write8(padapter, + (FW_8723A_START_ADDRESS + offset + i), + *(bufferPtr + offset + i)); + + if (ret == _FAIL) + goto exit; + } + } + +exit: + return ret; +} + +static int +_PageWrite(struct rtw_adapter *padapter, u32 page, void *buffer, u32 size) +{ + u8 value8; + u8 u8Page = (u8) (page & 0x07); + + value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page; + rtw_write8(padapter, REG_MCUFWDL + 2, value8); + + return _BlockWrite(padapter, buffer, size); +} + +static int _WriteFW(struct rtw_adapter *padapter, void *buffer, u32 size) +{ + /* Since we need dynamic decide method of dwonload fw, so we + call this function to get chip version. */ + /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ + int ret = _SUCCESS; + u32 pageNums, remainSize; + u32 page, offset; + u8 *bufferPtr = (u8 *) buffer; + + pageNums = size / MAX_PAGE_SIZE; + /* RT_ASSERT((pageNums <= 4), + ("Page numbers should not greater then 4 \n")); */ + remainSize = size % MAX_PAGE_SIZE; + + for (page = 0; page < pageNums; page++) { + offset = page * MAX_PAGE_SIZE; + ret = _PageWrite(padapter, page, bufferPtr + offset, + MAX_PAGE_SIZE); + + if (ret == _FAIL) + goto exit; + } + if (remainSize) { + offset = pageNums * MAX_PAGE_SIZE; + page = pageNums; + ret = _PageWrite(padapter, page, bufferPtr + offset, + remainSize); + + if (ret == _FAIL) + goto exit; + } + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("_WriteFW Done- for Normal chip.\n")); + +exit: + return ret; +} + +static s32 _FWFreeToGo(struct rtw_adapter *padapter) +{ + u32 counter = 0; + u32 value32; + + /* polling CheckSum report */ + do { + value32 = rtw_read32(padapter, REG_MCUFWDL); + if (value32 & FWDL_ChkSum_rpt) + break; + } while (counter++ < POLLING_READY_TIMEOUT_COUNT); + + if (counter >= POLLING_READY_TIMEOUT_COUNT) { + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", + __func__, value32)); + return _FAIL; + } + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, + value32)); + + value32 = rtw_read32(padapter, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + value32 &= ~WINTINI_RDY; + rtw_write32(padapter, REG_MCUFWDL, value32); + + /* polling for FW ready */ + counter = 0; + do { + value32 = rtw_read32(padapter, REG_MCUFWDL); + if (value32 & WINTINI_RDY) { + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("%s: Polling FW ready success!! " + "REG_MCUFWDL:0x%08x\n", + __func__, value32)); + return _SUCCESS; + } + udelay(5); + } while (counter++ < POLLING_READY_TIMEOUT_COUNT); + + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", + __func__, value32)); + return _FAIL; +} + +#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) + +void rtl8723a_FirmwareSelfReset(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 u1bTmp; + u8 Delay = 100; + + if (!(IS_FW_81xxC(padapter) && + ((pHalData->FirmwareVersion < 0x21) || + (pHalData->FirmwareVersion == 0x21 && + pHalData->FirmwareSubVersion < 0x01)))) { + /* after 88C Fw v33.1 */ + /* 0x1cf = 0x20. Inform 8051 to reset. 2009.12.25. tynli_test */ + rtw_write8(padapter, REG_HMETFR + 3, 0x20); + + u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); + while (u1bTmp & BIT2) { + Delay--; + if (Delay == 0) + break; + udelay(50); + u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); + } + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("-%s: 8051 reset success (%d)\n", __func__, + Delay)); + + if ((Delay == 0)) { + /* force firmware reset */ + u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); + rtw_write8(padapter, REG_SYS_FUNC_EN + 1, + u1bTmp & (~BIT2)); + } + } +} + +/* */ +/* Description: */ +/* Download 8192C firmware code. */ +/* */ +/* */ +s32 rtl8723a_FirmwareDownload(struct rtw_adapter *padapter) +{ + s32 rtStatus = _SUCCESS; + u8 writeFW_retry = 0; + unsigned long fwdl_start_time; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct device *device = dvobj_to_dev(dvobj); + struct rt_8723a_firmware_hdr *pFwHdr = NULL; + const struct firmware *fw; + char *fw_name; + u8 *firmware_buf = NULL; + u8 *buf; + int fw_size; + static int log_version; + + RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); + + if (IS_8723A_A_CUT(pHalData->VersionID)) { + fw_name = "rtlwifi/rtl8723aufw.bin"; + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("rtl8723a_FirmwareDownload: R8723FwImageArray_UMC " + "for RTL8723A A CUT\n")); + } else if (IS_8723A_B_CUT(pHalData->VersionID)) { + /* WLAN Fw. */ + if (padapter->registrypriv.wifi_spec == 1) { + fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin"; + DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithoutBT for " + "RTL8723A B CUT\n"); + } else { +#ifdef CONFIG_8723AU_BT_COEXIST + fw_name = "rtlwifi/rtl8723aufw_B.bin"; + DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithBT for " + "RTL8723A B CUT\n"); +#else + fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin"; + DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithoutBT for " + "RTL8723A B CUT\n"); +#endif + } + } else { + /* We should download proper RAM Code here + to match the ROM code. */ + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("%s: unknow version!\n", __func__)); + rtStatus = _FAIL; + goto Exit; + } + + pr_info("rtl8723au: Loading firmware %s\n", fw_name); + if (request_firmware(&fw, fw_name, device)) { + pr_err("rtl8723au: request_firmware load failed\n"); + rtStatus = _FAIL; + goto Exit; + } + if (!fw) { + pr_err("rtl8723au: Firmware %s not available\n", fw_name); + rtStatus = _FAIL; + goto Exit; + } + firmware_buf = kzalloc(fw->size, GFP_KERNEL); + if (!firmware_buf) { + rtStatus = _FAIL; + goto Exit; + } + memcpy(firmware_buf, fw->data, fw->size); + buf = firmware_buf; + fw_size = fw->size; + release_firmware(fw); + + /* To Check Fw header. Added by tynli. 2009.12.04. */ + pFwHdr = (struct rt_8723a_firmware_hdr *)firmware_buf; + + pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version); + pHalData->FirmwareSubVersion = pFwHdr->Subversion; + pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); + + DBG_8723A("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n", + __func__, pHalData->FirmwareVersion, + pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); + + if (!log_version++) + pr_info("%sFirmware Version %d, SubVersion %d, Signature " + "0x%x\n", DRIVER_PREFIX, pHalData->FirmwareVersion, + pHalData->FirmwareSubVersion, + pHalData->FirmwareSignature); + + if (IS_FW_HEADER_EXIST(pFwHdr)) { + /* Shift 32 bytes for FW header */ + buf = buf + 32; + fw_size = fw_size - 32; + } + + /* Suggested by Filen. If 8051 is running in RAM code, driver should + inform Fw to reset by itself, */ + /* or it will cause download Fw fail. 2010.02.01. by tynli. */ + if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { + /* 8051 RAM code */ + rtl8723a_FirmwareSelfReset(padapter); + rtw_write8(padapter, REG_MCUFWDL, 0x00); + } + + _FWDownloadEnable(padapter, true); + fwdl_start_time = jiffies; + while (1) { + /* reset the FWDL chksum */ + rtw_write8(padapter, REG_MCUFWDL, + rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt); + + rtStatus = _WriteFW(padapter, buf, fw_size); + + if (rtStatus == _SUCCESS || + (rtw_get_passing_time_ms23a(fwdl_start_time) > 500 && + writeFW_retry++ >= 3)) + break; + + DBG_8723A("%s writeFW_retry:%u, time after fwdl_start_time:" + "%ums\n", __func__, writeFW_retry, + jiffies_to_msecs(jiffies - fwdl_start_time)); + } + _FWDownloadEnable(padapter, false); + if (_SUCCESS != rtStatus) { + DBG_8723A("DL Firmware failed!\n"); + goto Exit; + } + + rtStatus = _FWFreeToGo(padapter); + if (_SUCCESS != rtStatus) { + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("DL Firmware failed!\n")); + goto Exit; + } + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("Firmware is ready to run!\n")); + +Exit: + kfree(firmware_buf); + return rtStatus; +} + +void rtl8723a_InitializeFirmwareVars(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* Init Fw LPS related. */ + padapter->pwrctrlpriv.bFwCurrentInPSMode = false; + + /* Init H2C counter. by tynli. 2009.12.09. */ + pHalData->LastHMEBoxNum = 0; +} + +static void rtl8723a_free_hal_data(struct rtw_adapter *padapter) +{ + + kfree(padapter->HalData); + padapter->HalData = NULL; + +} + +/* */ +/* Efuse related code */ +/* */ +static u8 +hal_EfuseSwitchToBank(struct rtw_adapter *padapter, u8 bank) +{ + u8 bRet = false; + u32 value32 = 0; + + DBG_8723A("%s: Efuse switch bank to %d\n", __func__, bank); + value32 = rtw_read32(padapter, EFUSE_TEST); + bRet = true; + switch (bank) { + case 0: + value32 = (value32 & ~EFUSE_SEL_MASK) | + EFUSE_SEL(EFUSE_WIFI_SEL_0); + break; + case 1: + value32 = (value32 & ~EFUSE_SEL_MASK) | + EFUSE_SEL(EFUSE_BT_SEL_0); + break; + case 2: + value32 = (value32 & ~EFUSE_SEL_MASK) | + EFUSE_SEL(EFUSE_BT_SEL_1); + break; + case 3: + value32 = (value32 & ~EFUSE_SEL_MASK) | + EFUSE_SEL(EFUSE_BT_SEL_2); + break; + default: + value32 = (value32 & ~EFUSE_SEL_MASK) | + EFUSE_SEL(EFUSE_WIFI_SEL_0); + bRet = false; + break; + } + rtw_write32(padapter, EFUSE_TEST, value32); + + return bRet; +} + +static void +Hal_GetEfuseDefinition(struct rtw_adapter *padapter, + u8 efuseType, u8 type, void *pOut) +{ + u8 *pu1Tmp; + u16 *pu2Tmp; + u8 *pMax_section; + + switch (type) { + case TYPE_EFUSE_MAX_SECTION: + pMax_section = (u8 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pMax_section = EFUSE_MAX_SECTION_8723A; + else + *pMax_section = EFUSE_BT_MAX_SECTION; + break; + + case TYPE_EFUSE_REAL_CONTENT_LEN: + pu2Tmp = (u16 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723A; + else + *pu2Tmp = EFUSE_BT_REAL_CONTENT_LEN; + break; + + case TYPE_AVAILABLE_EFUSE_BYTES_BANK: + pu2Tmp = (u16 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723A - + EFUSE_OOB_PROTECT_BYTES); + else + *pu2Tmp = (EFUSE_BT_REAL_BANK_CONTENT_LEN - + EFUSE_PROTECT_BYTES_BANK); + break; + + case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: + pu2Tmp = (u16 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723A - + EFUSE_OOB_PROTECT_BYTES); + else + *pu2Tmp = (EFUSE_BT_REAL_CONTENT_LEN - + (EFUSE_PROTECT_BYTES_BANK * 3)); + break; + + case TYPE_EFUSE_MAP_LEN: + pu2Tmp = (u16 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu2Tmp = EFUSE_MAP_LEN_8723A; + else + *pu2Tmp = EFUSE_BT_MAP_LEN; + break; + + case TYPE_EFUSE_PROTECT_BYTES_BANK: + pu1Tmp = (u8 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu1Tmp = EFUSE_OOB_PROTECT_BYTES; + else + *pu1Tmp = EFUSE_PROTECT_BYTES_BANK; + break; + + case TYPE_EFUSE_CONTENT_LEN_BANK: + pu2Tmp = (u16 *) pOut; + + if (efuseType == EFUSE_WIFI) + *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723A; + else + *pu2Tmp = EFUSE_BT_REAL_BANK_CONTENT_LEN; + break; + + default: + pu1Tmp = (u8 *) pOut; + *pu1Tmp = 0; + break; + } +} + +#define VOLTAGE_V25 0x03 +#define LDOE25_SHIFT 28 + +static void +Hal_EfusePowerSwitch(struct rtw_adapter *padapter, u8 bWrite, u8 PwrState) +{ + u8 tempval; + u16 tmpV16; + + if (PwrState == true) { + rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); + + /* 1.2V Power: From VDDON with Power + Cut(0x0000h[15]), defualt valid */ + tmpV16 = rtw_read16(padapter, REG_SYS_ISO_CTRL); + if (!(tmpV16 & PWC_EV12V)) { + tmpV16 |= PWC_EV12V; + rtw_write16(padapter, REG_SYS_ISO_CTRL, tmpV16); + } + /* Reset: 0x0000h[28], default valid */ + tmpV16 = rtw_read16(padapter, REG_SYS_FUNC_EN); + if (!(tmpV16 & FEN_ELDR)) { + tmpV16 |= FEN_ELDR; + rtw_write16(padapter, REG_SYS_FUNC_EN, tmpV16); + } + + /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock + from ANA, default valid */ + tmpV16 = rtw_read16(padapter, REG_SYS_CLKR); + if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { + tmpV16 |= (LOADER_CLK_EN | ANA8M); + rtw_write16(padapter, REG_SYS_CLKR, tmpV16); + } + + if (bWrite == true) { + /* Enable LDO 2.5V before read/write action */ + tempval = rtw_read8(padapter, EFUSE_TEST + 3); + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + rtw_write8(padapter, EFUSE_TEST + 3, (tempval | 0x80)); + } + } else { + rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); + + if (bWrite == true) { + /* Disable LDO 2.5V after read/write action */ + tempval = rtw_read8(padapter, EFUSE_TEST + 3); + rtw_write8(padapter, EFUSE_TEST + 3, (tempval & 0x7F)); + } + } +} + +static void +hal_ReadEFuse_WiFi(struct rtw_adapter *padapter, + u16 _offset, u16 _size_byte, u8 *pbuf) +{ + u8 *efuseTbl = NULL; + u16 eFuse_Addr = 0; + u8 offset, wden; + u8 efuseHeader, efuseExtHdr, efuseData; + u16 i, total, used; + + /* Do NOT excess total size of EFuse table. + Added by Roger, 2008.11.10. */ + if ((_offset + _size_byte) > EFUSE_MAP_LEN_8723A) { + DBG_8723A("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", + __func__, _offset, _size_byte); + return; + } + + efuseTbl = (u8 *) kmalloc(EFUSE_MAP_LEN_8723A, GFP_KERNEL); + if (efuseTbl == NULL) { + DBG_8723A("%s: alloc efuseTbl fail!\n", __func__); + return; + } + /* 0xff will be efuse default value instead of 0x00. */ + memset(efuseTbl, 0xFF, EFUSE_MAP_LEN_8723A); + + /* switch bank back to bank 0 for later BT and wifi use. */ + hal_EfuseSwitchToBank(padapter, 0); + + while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { + ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseHeader); + if (efuseHeader == 0xFF) { + DBG_8723A("%s: data end at address =%#x\n", __func__, + eFuse_Addr); + break; + } + + /* Check PG header for section num. */ + if (EXT_HEADER(efuseHeader)) { /* extended header */ + offset = GET_HDR_OFFSET_2_0(efuseHeader); + + ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseExtHdr); + if (ALL_WORDS_DISABLED(efuseExtHdr)) { + continue; + } + + offset |= ((efuseExtHdr & 0xF0) >> 1); + wden = (efuseExtHdr & 0x0F); + } else { + offset = ((efuseHeader >> 4) & 0x0f); + wden = (efuseHeader & 0x0f); + } + + if (offset < EFUSE_MAX_SECTION_8723A) { + u16 addr; + /* Get word enable value from PG header */ + + addr = offset * PGPKT_DATA_SIZE; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in the section */ + if (!(wden & (0x01 << i))) { + ReadEFuseByte23a(padapter, eFuse_Addr++, + &efuseData); + efuseTbl[addr] = efuseData; + + ReadEFuseByte23a(padapter, eFuse_Addr++, + &efuseData); + efuseTbl[addr + 1] = efuseData; + } + addr += 2; + } + } else { + DBG_8723A(KERN_ERR "%s: offset(%d) is illegal!!\n", + __func__, offset); + eFuse_Addr += Efuse_CalculateWordCnts23a(wden) * 2; + } + } + + /* Copy from Efuse map to output pointer memory!!! */ + for (i = 0; i < _size_byte; i++) + pbuf[i] = efuseTbl[_offset + i]; + + /* Calculate Efuse utilization */ + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); + used = eFuse_Addr - 1; + rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used); + + kfree(efuseTbl); +} + +static void +hal_ReadEFuse_BT(struct rtw_adapter *padapter, + u16 _offset, u16 _size_byte, u8 *pbuf) +{ + u8 *efuseTbl; + u8 bank; + u16 eFuse_Addr; + u8 efuseHeader, efuseExtHdr, efuseData; + u8 offset, wden; + u16 i, total, used; + + /* Do NOT excess total size of EFuse table. + Added by Roger, 2008.11.10. */ + if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) { + DBG_8723A("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", + __func__, _offset, _size_byte); + return; + } + + efuseTbl = kmalloc(EFUSE_BT_MAP_LEN, GFP_KERNEL); + if (efuseTbl == NULL) { + DBG_8723A("%s: efuseTbl malloc fail!\n", __func__); + return; + } + /* 0xff will be efuse default value instead of 0x00. */ + memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT, + TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total); + + for (bank = 1; bank < EFUSE_MAX_BANK; bank++) { + if (hal_EfuseSwitchToBank(padapter, bank) == false) { + DBG_8723A("%s: hal_EfuseSwitchToBank Fail!!\n", + __func__); + goto exit; + } + + eFuse_Addr = 0; + + while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { + ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseHeader); + if (efuseHeader == 0xFF) + break; + + /* Check PG header for section num. */ + if (EXT_HEADER(efuseHeader)) { /* extended header */ + offset = GET_HDR_OFFSET_2_0(efuseHeader); + + ReadEFuseByte23a(padapter, eFuse_Addr++, + &efuseExtHdr); + if (ALL_WORDS_DISABLED(efuseExtHdr)) { + continue; + } + + offset |= ((efuseExtHdr & 0xF0) >> 1); + wden = (efuseExtHdr & 0x0F); + } else { + offset = ((efuseHeader >> 4) & 0x0f); + wden = (efuseHeader & 0x0f); + } + + if (offset < EFUSE_BT_MAX_SECTION) { + u16 addr; + + /* Get word enable value from PG header */ + + addr = offset * PGPKT_DATA_SIZE; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in + the section */ + if (!(wden & (0x01 << i))) { + ReadEFuseByte23a(padapter, + eFuse_Addr++, + &efuseData); + efuseTbl[addr] = efuseData; + + ReadEFuseByte23a(padapter, + eFuse_Addr++, + &efuseData); + efuseTbl[addr + 1] = efuseData; + } + addr += 2; + } + } else { + DBG_8723A(KERN_ERR + "%s: offset(%d) is illegal!!\n", + __func__, offset); + eFuse_Addr += Efuse_CalculateWordCnts23a(wden) * 2; + } + } + + if ((eFuse_Addr - 1) < total) { + DBG_8723A("%s: bank(%d) data end at %#x\n", + __func__, bank, eFuse_Addr - 1); + break; + } + } + + /* switch bank back to bank 0 for later BT and wifi use. */ + hal_EfuseSwitchToBank(padapter, 0); + + /* Copy from Efuse map to output pointer memory!!! */ + for (i = 0; i < _size_byte; i++) + pbuf[i] = efuseTbl[_offset + i]; + + /* */ + /* Calculate Efuse utilization. */ + /* */ + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total); + used = (EFUSE_BT_REAL_BANK_CONTENT_LEN * (bank - 1)) + eFuse_Addr - 1; + rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &used); + +exit: + kfree(efuseTbl); +} + +static void +Hal_ReadEFuse(struct rtw_adapter *padapter, + u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf) +{ + if (efuseType == EFUSE_WIFI) + hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf); + else + hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf); +} + +static u16 +hal_EfuseGetCurrentSize_WiFi(struct rtw_adapter *padapter) +{ + u16 efuse_addr = 0; + u8 hoffset = 0, hworden = 0; + u8 efuse_data, word_cnts = 0; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr); + + DBG_8723A("%s: start_efuse_addr = 0x%X\n", __func__, efuse_addr); + + /* switch bank back to bank 0 for later BT and wifi use. */ + hal_EfuseSwitchToBank(padapter, 0); + + while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { + if (efuse_OneByteRead23a(padapter, efuse_addr, &efuse_data) == + false) { + DBG_8723A(KERN_ERR "%s: efuse_OneByteRead23a Fail! " + "addr = 0x%X !!\n", __func__, efuse_addr); + break; + } + + if (efuse_data == 0xFF) + break; + + if (EXT_HEADER(efuse_data)) { + hoffset = GET_HDR_OFFSET_2_0(efuse_data); + efuse_addr++; + efuse_OneByteRead23a(padapter, efuse_addr, &efuse_data); + if (ALL_WORDS_DISABLED(efuse_data)) { + continue; + } + + hoffset |= ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } else { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + } + + word_cnts = Efuse_CalculateWordCnts23a(hworden); + efuse_addr += (word_cnts * 2) + 1; + } + + rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr); + + DBG_8723A("%s: CurrentSize =%d\n", __func__, efuse_addr); + + return efuse_addr; +} + +static u16 +hal_EfuseGetCurrentSize_BT(struct rtw_adapter *padapter) +{ + u16 btusedbytes; + u16 efuse_addr; + u8 bank, startBank; + u8 hoffset = 0, hworden = 0; + u8 efuse_data, word_cnts = 0; + u16 retU2 = 0; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &btusedbytes); + + efuse_addr = (u16) ((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN)); + startBank = (u8) (1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN)); + + DBG_8723A("%s: start from bank =%d addr = 0x%X\n", __func__, startBank, + efuse_addr); + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT, + TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2); + + for (bank = startBank; bank < EFUSE_MAX_BANK; bank++) { + if (hal_EfuseSwitchToBank(padapter, bank) == false) { + DBG_8723A(KERN_ERR "%s: switch bank(%d) Fail!!\n", + __func__, bank); + bank = EFUSE_MAX_BANK; + break; + } + + /* only when bank is switched we have to reset + the efuse_addr. */ + if (bank != startBank) + efuse_addr = 0; + + while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { + if (efuse_OneByteRead23a(padapter, efuse_addr, + &efuse_data) == false) { + DBG_8723A(KERN_ERR "%s: efuse_OneByteRead23a Fail!" + " addr = 0x%X !!\n", + __func__, efuse_addr); + bank = EFUSE_MAX_BANK; + break; + } + + if (efuse_data == 0xFF) + break; + + if (EXT_HEADER(efuse_data)) { + hoffset = GET_HDR_OFFSET_2_0(efuse_data); + efuse_addr++; + efuse_OneByteRead23a(padapter, efuse_addr, + &efuse_data); + if (ALL_WORDS_DISABLED(efuse_data)) { + efuse_addr++; + continue; + } + + hoffset |= ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } else { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + } + word_cnts = Efuse_CalculateWordCnts23a(hworden); + /* read next header */ + efuse_addr += (word_cnts * 2) + 1; + } + + /* Check if we need to check next bank efuse */ + if (efuse_addr < retU2) { + break; /* don't need to check next bank. */ + } + } + + retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr; + rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&retU2); + + DBG_8723A("%s: CurrentSize =%d\n", __func__, retU2); + return retU2; +} + +static u16 +Hal_EfuseGetCurrentSize(struct rtw_adapter *pAdapter, u8 efuseType) +{ + u16 ret = 0; + + if (efuseType == EFUSE_WIFI) + ret = hal_EfuseGetCurrentSize_WiFi(pAdapter); + else + ret = hal_EfuseGetCurrentSize_BT(pAdapter); + + return ret; +} + +static u8 +Hal_EfuseWordEnableDataWrite(struct rtw_adapter *padapter, + u16 efuse_addr, u8 word_en, u8 *data) +{ + u16 tmpaddr = 0; + u16 start_addr = efuse_addr; + u8 badworden = 0x0F; + u8 tmpdata[PGPKT_DATA_SIZE]; + + memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); + + if (!(word_en & BIT(0))) { + tmpaddr = start_addr; + efuse_OneByteWrite23a(padapter, start_addr++, data[0]); + efuse_OneByteWrite23a(padapter, start_addr++, data[1]); + + efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[0]); + efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[1]); + if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) { + badworden &= (~BIT(0)); + } + } + if (!(word_en & BIT(1))) { + tmpaddr = start_addr; + efuse_OneByteWrite23a(padapter, start_addr++, data[2]); + efuse_OneByteWrite23a(padapter, start_addr++, data[3]); + + efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[2]); + efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[3]); + if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) { + badworden &= (~BIT(1)); + } + } + if (!(word_en & BIT(2))) { + tmpaddr = start_addr; + efuse_OneByteWrite23a(padapter, start_addr++, data[4]); + efuse_OneByteWrite23a(padapter, start_addr++, data[5]); + + efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[4]); + efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[5]); + if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) { + badworden &= (~BIT(2)); + } + } + if (!(word_en & BIT(3))) { + tmpaddr = start_addr; + efuse_OneByteWrite23a(padapter, start_addr++, data[6]); + efuse_OneByteWrite23a(padapter, start_addr++, data[7]); + + efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[6]); + efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[7]); + if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) { + badworden &= (~BIT(3)); + } + } + + return badworden; +} + +static s32 +Hal_EfusePgPacketRead(struct rtw_adapter *padapter, u8 offset, u8 *data) +{ + u8 efuse_data, word_cnts = 0; + u16 efuse_addr = 0; + u8 hoffset = 0, hworden = 0; + u8 i; + u8 max_section = 0; + s32 ret; + + if (data == NULL) + return false; + + EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, + &max_section); + if (offset > max_section) { + DBG_8723A("%s: Packet offset(%d) is illegal(>%d)!\n", + __func__, offset, max_section); + return false; + } + + memset(data, 0xFF, PGPKT_DATA_SIZE); + ret = true; + + /* */ + /* Efuse has been pre-programmed dummy 5Bytes at the + end of Efuse by CP. */ + /* Skip dummy parts to prevent unexpected data read from Efuse. */ + /* By pass right now. 2009.02.19. */ + /* */ + while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { + if (efuse_OneByteRead23a(padapter, efuse_addr++, &efuse_data) == + false) { + ret = false; + break; + } + + if (efuse_data == 0xFF) + break; + + if (EXT_HEADER(efuse_data)) { + hoffset = GET_HDR_OFFSET_2_0(efuse_data); + efuse_OneByteRead23a(padapter, efuse_addr++, &efuse_data); + if (ALL_WORDS_DISABLED(efuse_data)) { + DBG_8723A("%s: Error!! All words disabled!\n", + __func__); + continue; + } + + hoffset |= ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } else { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + } + + if (hoffset == offset) { + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in the section */ + if (!(hworden & (0x01 << i))) { + ReadEFuseByte23a(padapter, efuse_addr++, + &efuse_data); + data[i * 2] = efuse_data; + + ReadEFuseByte23a(padapter, efuse_addr++, + &efuse_data); + data[(i * 2) + 1] = efuse_data; + } + } + } else { + word_cnts = Efuse_CalculateWordCnts23a(hworden); + efuse_addr += word_cnts * 2; + } + } + + return ret; +} + +static u8 +hal_EfusePgCheckAvailableAddr(struct rtw_adapter *pAdapter, u8 efuseType) +{ + u16 max_available = 0; + u16 current_size; + + EFUSE_GetEfuseDefinition23a(pAdapter, efuseType, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, + &max_available); + + current_size = Efuse_GetCurrentSize23a(pAdapter, efuseType); + if (current_size >= max_available) { + DBG_8723A("%s: Error!! current_size(%d)>max_available(%d)\n", + __func__, current_size, max_available); + return false; + } + return true; +} + +static void +hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, + struct pg_pkt_struct *pTargetPkt) +{ + memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); + pTargetPkt->offset = offset; + pTargetPkt->word_en = word_en; + efuse_WordEnableDataRead23a(word_en, pData, pTargetPkt->data); + pTargetPkt->word_cnts = Efuse_CalculateWordCnts23a(pTargetPkt->word_en); +} + +static u8 +hal_EfusePartialWriteCheck(struct rtw_adapter *padapter, u8 efuseType, + u16 *pAddr, struct pg_pkt_struct *pTargetPkt) +{ + u8 bRet = false; + u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; + u8 efuse_data = 0; + + EFUSE_GetEfuseDefinition23a(padapter, efuseType, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, + &efuse_max_available_len); + EFUSE_GetEfuseDefinition23a(padapter, efuseType, + TYPE_EFUSE_CONTENT_LEN_BANK, &efuse_max); + + if (efuseType == EFUSE_WIFI) { + rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, + (u8 *) &startAddr); + } else { + rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, + (u8 *) &startAddr); + } + startAddr %= efuse_max; + + while (1) { + if (startAddr >= efuse_max_available_len) { + bRet = false; + DBG_8723A("%s: startAddr(%d) >= efuse_max_available_" + "len(%d)\n", __func__, startAddr, + efuse_max_available_len); + break; + } + + if (efuse_OneByteRead23a(padapter, startAddr, &efuse_data) && + (efuse_data != 0xFF)) { + bRet = false; + DBG_8723A("%s: Something Wrong! last bytes(%#X = 0x%02X) " + "is not 0xFF\n", __func__, + startAddr, efuse_data); + break; + } else { + /* not used header, 0xff */ + *pAddr = startAddr; + bRet = true; + break; + } + } + + return bRet; +} + +static u8 +hal_EfusePgPacketWrite1ByteHeader(struct rtw_adapter *pAdapter, u8 efuseType, + u16 *pAddr, struct pg_pkt_struct *pTargetPkt) +{ + u8 pg_header = 0, tmp_header = 0; + u16 efuse_addr = *pAddr; + u8 repeatcnt = 0; + + pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; + + do { + efuse_OneByteWrite23a(pAdapter, efuse_addr, pg_header); + efuse_OneByteRead23a(pAdapter, efuse_addr, &tmp_header); + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + DBG_8723A("%s: Repeat over limit for pg_header!!\n", + __func__); + return false; + } + } while (1); + + if (tmp_header != pg_header) { + DBG_8723A(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X " + "read = 0x%02X)\n", __func__, + pg_header, tmp_header); + return false; + } + + *pAddr = efuse_addr; + + return true; +} + +static u8 +hal_EfusePgPacketWrite2ByteHeader(struct rtw_adapter *padapter, u8 efuseType, + u16 *pAddr, struct pg_pkt_struct *pTargetPkt) +{ + u16 efuse_addr, efuse_max_available_len = 0; + u8 pg_header = 0, tmp_header = 0; + u8 repeatcnt = 0; + + EFUSE_GetEfuseDefinition23a(padapter, efuseType, + TYPE_AVAILABLE_EFUSE_BYTES_BANK, + &efuse_max_available_len); + + efuse_addr = *pAddr; + if (efuse_addr >= efuse_max_available_len) { + DBG_8723A("%s: addr(%d) over avaliable(%d)!!\n", __func__, + efuse_addr, efuse_max_available_len); + return false; + } + + pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; + + do { + efuse_OneByteWrite23a(padapter, efuse_addr, pg_header); + efuse_OneByteRead23a(padapter, efuse_addr, &tmp_header); + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + DBG_8723A("%s: Repeat over limit for pg_header!!\n", + __func__); + return false; + } + } while (1); + + if (tmp_header != pg_header) { + DBG_8723A(KERN_ERR + "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n", + __func__, pg_header, tmp_header); + return false; + } + + /* to write ext_header */ + efuse_addr++; + pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; + + do { + efuse_OneByteWrite23a(padapter, efuse_addr, pg_header); + efuse_OneByteRead23a(padapter, efuse_addr, &tmp_header); + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + DBG_8723A("%s: Repeat over limit for ext_header!!\n", + __func__); + return false; + } + } while (1); + + if (tmp_header != pg_header) { /* offset PG fail */ + DBG_8723A(KERN_ERR + "%s: PG EXT Header Fail!!(pg = 0x%02X read = 0x%02X)\n", + __func__, pg_header, tmp_header); + return false; + } + + *pAddr = efuse_addr; + + return true; +} + +static u8 +hal_EfusePgPacketWriteHeader(struct rtw_adapter *padapter, u8 efuseType, + u16 *pAddr, struct pg_pkt_struct *pTargetPkt) +{ + u8 bRet = false; + + if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) { + bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, + pAddr, pTargetPkt); + } else { + bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, + pAddr, pTargetPkt); + } + + return bRet; +} + +static u8 +hal_EfusePgPacketWriteData(struct rtw_adapter *pAdapter, u8 efuseType, + u16 *pAddr, struct pg_pkt_struct *pTargetPkt) +{ + u16 efuse_addr; + u8 badworden; + + efuse_addr = *pAddr; + badworden = + Efuse_WordEnableDataWrite23a(pAdapter, efuse_addr + 1, + pTargetPkt->word_en, pTargetPkt->data); + if (badworden != 0x0F) { + DBG_8723A("%s: Fail!!\n", __func__); + return false; + } + + return true; +} + +static s32 +Hal_EfusePgPacketWrite(struct rtw_adapter *padapter, + u8 offset, u8 word_en, u8 *pData) +{ + struct pg_pkt_struct targetPkt; + u16 startAddr = 0; + u8 efuseType = EFUSE_WIFI; + + if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType)) + return false; + + hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); + + if (!hal_EfusePartialWriteCheck(padapter, efuseType, + &startAddr, &targetPkt)) + return false; + + if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, + &startAddr, &targetPkt)) + return false; + + if (!hal_EfusePgPacketWriteData(padapter, efuseType, + &startAddr, &targetPkt)) + return false; + + return true; +} + +static bool +Hal_EfusePgPacketWrite_BT(struct rtw_adapter *pAdapter, + u8 offset, u8 word_en, u8 *pData) +{ + struct pg_pkt_struct targetPkt; + u16 startAddr = 0; + u8 efuseType = EFUSE_BT; + + if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType)) + return false; + + hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); + + if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, + &startAddr, &targetPkt)) + return false; + + if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, + &startAddr, &targetPkt)) + return false; + + if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, + &startAddr, &targetPkt)) + return false; + + return true; +} + +static struct hal_version ReadChipVersion8723A(struct rtw_adapter *padapter) +{ + u32 value32; + struct hal_version ChipVersion; + struct hal_data_8723a *pHalData; + + pHalData = GET_HAL_DATA(padapter); + + value32 = rtw_read32(padapter, REG_SYS_CFG); + ChipVersion.ICType = CHIP_8723A; + ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); + ChipVersion.RFType = RF_TYPE_1T1R; + ChipVersion.VendorType = + ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); + ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK) >> CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ + + /* For regulator mode. by tynli. 2011.01.14 */ + pHalData->RegulatorMode = ((value32 & SPS_SEL) ? + RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); + + value32 = rtw_read32(padapter, REG_GPIO_OUTSTS); + /* ROM code version. */ + ChipVersion.ROMVer = ((value32 & RF_RL_ID) >> 20); + + /* For multi-function consideration. Added by Roger, 2010.10.06. */ + pHalData->MultiFunc = RT_MULTI_FUNC_NONE; + value32 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL); + pHalData->MultiFunc |= + ((value32 & WL_FUNC_EN) ? RT_MULTI_FUNC_WIFI : 0); + pHalData->MultiFunc |= ((value32 & BT_FUNC_EN) ? RT_MULTI_FUNC_BT : 0); + pHalData->MultiFunc |= + ((value32 & GPS_FUNC_EN) ? RT_MULTI_FUNC_GPS : 0); + pHalData->PolarityCtl = + ((value32 & WL_HWPDN_SL) ? RT_POLARITY_HIGH_ACT : + RT_POLARITY_LOW_ACT); + dump_chip_info23a(ChipVersion); + pHalData->VersionID = ChipVersion; + + if (IS_1T2R(ChipVersion)) + pHalData->rf_type = RF_1T2R; + else if (IS_2T2R(ChipVersion)) + pHalData->rf_type = RF_2T2R; + else + pHalData->rf_type = RF_1T1R; + + MSG_8723A("RF_Type is %x!!\n", pHalData->rf_type); + + return ChipVersion; +} + +static void rtl8723a_read_chip_version(struct rtw_adapter *padapter) +{ + ReadChipVersion8723A(padapter); +} + +/* */ +/* */ +/* 20100209 Joseph: */ +/* This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */ +/* We just reserve the value of the register in variable + pHalData->RegBcnCtrlVal and then operate */ +/* the value of the register via atomic operation. */ +/* This prevents from race condition when setting this register. */ +/* The value of pHalData->RegBcnCtrlVal is initialized in + HwConfigureRTL8192CE() function. */ +/* */ +void SetBcnCtrlReg23a(struct rtw_adapter *padapter, u8 SetBits, u8 ClearBits) +{ + struct hal_data_8723a *pHalData; + u32 addr; + u8 *pRegBcnCtrlVal; + + pHalData = GET_HAL_DATA(padapter); + pRegBcnCtrlVal = (u8 *)&pHalData->RegBcnCtrlVal; + + addr = REG_BCN_CTRL; + + *pRegBcnCtrlVal = rtw_read8(padapter, addr); + *pRegBcnCtrlVal |= SetBits; + *pRegBcnCtrlVal &= ~ClearBits; + + rtw_write8(padapter, addr, *pRegBcnCtrlVal); +} + +void rtl8723a_InitBeaconParameters(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + rtw_write16(padapter, REG_BCN_CTRL, 0x1010); + pHalData->RegBcnCtrlVal = 0x1010; + + /* TODO: Remove these magic number */ + rtw_write16(padapter, REG_TBTT_PROHIBIT, 0x6404); /* ms */ + /* Firmware will control REG_DRVERLYINT when power saving is enable, */ + /* so don't set this register on STA mode. */ + if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == false) + rtw_write8(padapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME); + /* 2ms */ + rtw_write8(padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); + + /* Suggested by designer timchen. Change beacon AIFS to the + largest number beacause test chip does not contension before + sending beacon. by tynli. 2009.11.03 */ + rtw_write16(padapter, REG_BCNTCFG, 0x660F); +} + +static void ResumeTxBeacon(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause + we record the value */ + /* which should be read from register to a global variable. */ + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+ResumeTxBeacon\n")); + + pHalData->RegFwHwTxQCtrl |= BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, 0xff); + pHalData->RegReg542 |= BIT(0); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, pHalData->RegReg542); +} + +static void StopTxBeacon(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause + we record the value */ + /* which should be read from register to a global variable. */ + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+StopTxBeacon\n")); + + pHalData->RegFwHwTxQCtrl &= ~BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, 0x64); + pHalData->RegReg542 &= ~BIT(0); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, pHalData->RegReg542); + + CheckFwRsvdPageContent23a(padapter); /* 2010.06.23. Added by tynli. */ +} + +static void _BeaconFunctionEnable(struct rtw_adapter *padapter, u8 Enable, + u8 Linked) +{ + SetBcnCtrlReg23a(padapter, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB, + 0); + rtw_write8(padapter, REG_RD_CTRL + 1, 0x6F); +} + +static void rtl8723a_SetBeaconRelatedRegisters(struct rtw_adapter *padapter) +{ + u32 value32; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* reset TSF, enable update TSF, correcting TSF On Beacon */ + + /* REG_BCN_INTERVAL */ + /* REG_BCNDMATIM */ + /* REG_ATIMWND */ + /* REG_TBTT_PROHIBIT */ + /* REG_DRVERLYINT */ + /* REG_BCN_MAX_ERR */ + /* REG_BCNTCFG (0x510) */ + /* REG_DUAL_TSF_RST */ + /* REG_BCN_CTRL (0x550) */ + + /* */ + /* ATIM window */ + /* */ + rtw_write16(padapter, REG_ATIMWND, 2); + + /* */ + /* Beacon interval (in unit of TU). */ + /* */ + rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); + + rtl8723a_InitBeaconParameters(padapter); + + rtw_write8(padapter, REG_SLOT, 0x09); + + /* */ + /* Reset TSF Timer to zero, added by Roger. 2008.06.24 */ + /* */ + value32 = rtw_read32(padapter, REG_TCR); + value32 &= ~TSFRST; + rtw_write32(padapter, REG_TCR, value32); + + value32 |= TSFRST; + rtw_write32(padapter, REG_TCR, value32); + + /* NOTE: Fix test chip's bug (about contention windows's randomness) */ + if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE | + WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE) == true) { + rtw_write8(padapter, REG_RXTSF_OFFSET_CCK, 0x50); + rtw_write8(padapter, REG_RXTSF_OFFSET_OFDM, 0x50); + } + + _BeaconFunctionEnable(padapter, true, true); + + ResumeTxBeacon(padapter); + SetBcnCtrlReg23a(padapter, DIS_BCNQ_SUB, 0); +} + +static void rtl8723a_GetHalODMVar(struct rtw_adapter *Adapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet) +{ + switch (eVariable) { + case HAL_ODM_STA_INFO: + break; + default: + break; + } +} + +static void rtl8723a_SetHalODMVar(struct rtw_adapter *Adapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_odm_t *podmpriv = &pHalData->odmpriv; + switch (eVariable) { + case HAL_ODM_STA_INFO: + { + struct sta_info *psta = (struct sta_info *)pValue1; + + if (bSet) { + DBG_8723A("Set STA_(%d) info\n", psta->mac_id); + ODM_CmnInfoPtrArrayHook23a(podmpriv, + ODM_CMNINFO_STA_STATUS, + psta->mac_id, psta); + } else { + DBG_8723A("Clean STA_(%d) info\n", psta->mac_id); + ODM_CmnInfoPtrArrayHook23a(podmpriv, + ODM_CMNINFO_STA_STATUS, + psta->mac_id, NULL); + } + } + break; + case HAL_ODM_P2P_STATE: + ODM_CmnInfoUpdate23a(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet); + break; + case HAL_ODM_WIFI_DISPLAY_STATE: + ODM_CmnInfoUpdate23a(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); + break; + default: + break; + } +} + +static void hal_notch_filter_8723a(struct rtw_adapter *adapter, bool enable) +{ + if (enable) { + DBG_8723A("Enable notch filter\n"); + rtw_write8(adapter, rOFDM0_RxDSP + 1, + rtw_read8(adapter, rOFDM0_RxDSP + 1) | BIT1); + } else { + DBG_8723A("Disable notch filter\n"); + rtw_write8(adapter, rOFDM0_RxDSP + 1, + rtw_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT1); + } +} + +s32 c2h_id_filter_ccx_8723a(u8 id) +{ + s32 ret = false; + if (id == C2H_CCX_TX_RPT) + ret = true; + + return ret; +} + +static s32 c2h_handler_8723a(struct rtw_adapter *padapter, + struct c2h_evt_hdr *c2h_evt) +{ + s32 ret = _SUCCESS; + u8 i = 0; + + if (c2h_evt == NULL) { + DBG_8723A("%s c2h_evt is NULL\n", __func__); + ret = _FAIL; + goto exit; + } + + switch (c2h_evt->id) { + case C2H_DBG: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("C2HCommandHandler: %s\n", c2h_evt->payload)); + break; + + case C2H_CCX_TX_RPT: + handle_txrpt_ccx_8723a(padapter, c2h_evt->payload); + break; + case C2H_EXT_RA_RPT: + break; + case C2H_HW_INFO_EXCH: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("[BT], C2H_HW_INFO_EXCH\n")); + for (i = 0; i < c2h_evt->plen; i++) { + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("[BT], tmpBuf[%d]= 0x%x\n", i, + c2h_evt->payload[i])); + } + break; + + case C2H_C2H_H2C_TEST: + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("[BT], C2H_H2C_TEST\n")); + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("[BT], tmpBuf[0]/[1]/[2]/[3]/[4]= 0x%x/ 0x%x/ " + "0x%x/ 0x%x/ 0x%x\n", c2h_evt->payload[0], + c2h_evt->payload[1], c2h_evt->payload[2], + c2h_evt->payload[3], c2h_evt->payload[4])); + break; + +#ifdef CONFIG_8723AU_BT_COEXIST + case C2H_BT_INFO: + DBG_8723A("%s , Got C2H_BT_INFO \n", __func__); + BT_FwC2hBtInfo(padapter, c2h_evt->payload, c2h_evt->plen); + break; +#endif + + default: + ret = _FAIL; + break; + } + +exit: + return ret; +} + +void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc) +{ + pHalFunc->free_hal_data = &rtl8723a_free_hal_data; + + pHalFunc->dm_init = &rtl8723a_init_dm_priv; + pHalFunc->dm_deinit = &rtl8723a_deinit_dm_priv; + + pHalFunc->read_chip_version = &rtl8723a_read_chip_version; + + pHalFunc->set_bwmode_handler = &PHY_SetBWMode23a8723A; + pHalFunc->set_channel_handler = &PHY_SwChnl8723A; + + pHalFunc->hal_dm_watchdog = &rtl8723a_HalDmWatchDog; + + pHalFunc->SetBeaconRelatedRegistersHandler = + &rtl8723a_SetBeaconRelatedRegisters; + + pHalFunc->Add_RateATid = &rtl8723a_add_rateatid; + pHalFunc->run_thread = &rtl8723a_start_thread; + pHalFunc->cancel_thread = &rtl8723a_stop_thread; + + pHalFunc->read_bbreg = &PHY_QueryBBReg; + pHalFunc->write_bbreg = &PHY_SetBBReg; + pHalFunc->read_rfreg = &PHY_QueryRFReg; + pHalFunc->write_rfreg = &PHY_SetRFReg; + + /* Efuse related function */ + pHalFunc->EfusePowerSwitch = &Hal_EfusePowerSwitch; + pHalFunc->ReadEFuse = &Hal_ReadEFuse; + pHalFunc->EFUSEGetEfuseDefinition = &Hal_GetEfuseDefinition; + pHalFunc->EfuseGetCurrentSize = &Hal_EfuseGetCurrentSize; + pHalFunc->Efuse_PgPacketRead23a = &Hal_EfusePgPacketRead; + pHalFunc->Efuse_PgPacketWrite23a = &Hal_EfusePgPacketWrite; + pHalFunc->Efuse_WordEnableDataWrite23a = &Hal_EfuseWordEnableDataWrite; + pHalFunc->Efuse_PgPacketWrite23a_BT = &Hal_EfusePgPacketWrite_BT; + + pHalFunc->sreset_init_value23a = &sreset_init_value23a; + pHalFunc->sreset_reset_value23a = &sreset_reset_value23a; + pHalFunc->silentreset = &sreset_reset; + pHalFunc->sreset_xmit_status_check = &rtl8723a_sreset_xmit_status_check; + pHalFunc->sreset_linked_status_check = + &rtl8723a_sreset_linked_status_check; + pHalFunc->sreset_get_wifi_status23a = &sreset_get_wifi_status23a; + pHalFunc->sreset_inprogress = &sreset_inprogress; + pHalFunc->GetHalODMVarHandler = &rtl8723a_GetHalODMVar; + pHalFunc->SetHalODMVarHandler = &rtl8723a_SetHalODMVar; + + pHalFunc->hal_notch_filter = &hal_notch_filter_8723a; + + pHalFunc->c2h_handler = c2h_handler_8723a; + pHalFunc->c2h_id_filter_ccx = c2h_id_filter_ccx_8723a; +} + +void rtl8723a_InitAntenna_Selection(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + u8 val; + + pHalData = GET_HAL_DATA(padapter); + + val = rtw_read8(padapter, REG_LEDCFG2); + /* Let 8051 take control antenna settting */ + val |= BIT(7); /* DPDT_SEL_EN, 0x4C[23] */ + rtw_write8(padapter, REG_LEDCFG2, val); +} + +void rtl8723a_CheckAntenna_Selection(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + u8 val; + + pHalData = GET_HAL_DATA(padapter); + + val = rtw_read8(padapter, REG_LEDCFG2); + /* Let 8051 take control antenna settting */ + if (!(val & BIT(7))) { + val |= BIT(7); /* DPDT_SEL_EN, 0x4C[23] */ + rtw_write8(padapter, REG_LEDCFG2, val); + } +} + +void rtl8723a_DeinitAntenna_Selection(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + u8 val; + + pHalData = GET_HAL_DATA(padapter); + val = rtw_read8(padapter, REG_LEDCFG2); + /* Let 8051 take control antenna settting */ + val &= ~BIT(7); /* DPDT_SEL_EN, clear 0x4C[23] */ + rtw_write8(padapter, REG_LEDCFG2, val); +} + +void rtl8723a_init_default_value(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct dm_priv *pdmpriv; + u8 i; + + pHalData = GET_HAL_DATA(padapter); + pdmpriv = &pHalData->dmpriv; + + /* init default value */ + pHalData->fw_ractrl = false; + pHalData->bIQKInitialized = false; + if (!padapter->pwrctrlpriv.bkeepfwalive) + pHalData->LastHMEBoxNum = 0; + + pHalData->bIQKInitialized = false; + + /* init dm default value */ + pdmpriv->TM_Trigger = 0; /* for IQK */ +/* pdmpriv->binitialized = false; */ +/* pdmpriv->prv_traffic_idx = 3; */ +/* pdmpriv->initialize = 0; */ + + pdmpriv->ThermalValue_HP_index = 0; + for (i = 0; i < HP_THERMAL_NUM; i++) + pdmpriv->ThermalValue_HP[i] = 0; + + /* init Efuse variables */ + pHalData->EfuseUsedBytes = 0; + pHalData->BTEfuseUsedBytes = 0; +} + +u8 GetEEPROMSize8723A(struct rtw_adapter *padapter) +{ + u8 size = 0; + u32 cr; + + cr = rtw_read16(padapter, REG_9346CR); + /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ + size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; + + MSG_8723A("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46"); + + return size; +} + +/* */ +/* */ +/* LLT R/W/Init function */ +/* */ +/* */ +static s32 _LLTWrite(struct rtw_adapter *padapter, u32 address, u32 data) +{ + s32 status = _SUCCESS; + s32 count = 0; + u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | + _LLT_OP(_LLT_WRITE_ACCESS); + u16 LLTReg = REG_LLT_INIT; + + rtw_write32(padapter, LLTReg, value); + + /* polling */ + do { + value = rtw_read32(padapter, LLTReg); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) { + break; + } + + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(_module_hal_init_c_, _drv_err_, + ("Failed to polling write LLT done at " + "address %d!\n", address)); + status = _FAIL; + break; + } + } while (count++); + + return status; +} + +s32 InitLLTTable23a(struct rtw_adapter *padapter, u32 boundary) +{ + s32 status = _SUCCESS; + u32 i; + u32 txpktbuf_bndy = boundary; + u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER; + + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _LLTWrite(padapter, i, i + 1); + if (_SUCCESS != status) { + return status; + } + } + + /* end of list */ + status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF); + if (_SUCCESS != status) { + return status; + } + + /* Make the other pages as ring buffer */ + /* This ring buffer is used as beacon buffer if we config this + MAC as two MAC transfer. */ + /* Otherwise used as local loopback buffer. */ + for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) { + status = _LLTWrite(padapter, i, (i + 1)); + if (_SUCCESS != status) { + return status; + } + } + + /* Let last entry point to the start entry of ring buffer */ + status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy); + if (_SUCCESS != status) { + return status; + } + + return status; +} + +static void _DisableGPIO(struct rtw_adapter *padapter) +{ +/*************************************** +j. GPIO_PIN_CTRL 0x44[31:0]= 0x000 +k.Value = GPIO_PIN_CTRL[7:0] +l. GPIO_PIN_CTRL 0x44[31:0] = 0x00FF0000 | (value <<8); write external PIN level +m. GPIO_MUXCFG 0x42 [15:0] = 0x0780 +n. LEDCFG 0x4C[15:0] = 0x8080 +***************************************/ + u32 value32; + u32 u4bTmp; + + /* 1. Disable GPIO[7:0] */ + rtw_write16(padapter, REG_GPIO_PIN_CTRL + 2, 0x0000); + value32 = rtw_read32(padapter, REG_GPIO_PIN_CTRL) & 0xFFFF00FF; + u4bTmp = value32 & 0x000000FF; + value32 |= ((u4bTmp << 8) | 0x00FF0000); + rtw_write32(padapter, REG_GPIO_PIN_CTRL, value32); + + /* */ + /* For RTL8723u multi-function configuration which + was autoload from Efuse offset 0x0a and 0x0b, */ + /* WLAN HW GPIO[9], GPS HW GPIO[10] and BT HW GPIO[11]. */ + /* Added by Roger, 2010.10.07. */ + /* */ + /* 2. Disable GPIO[8] and GPIO[12] */ + + /* Configure all pins as input mode. */ + rtw_write16(padapter, REG_GPIO_IO_SEL_2, 0x0000); + value32 = rtw_read32(padapter, REG_GPIO_PIN_CTRL_2) & 0xFFFF001F; + u4bTmp = value32 & 0x0000001F; + /* Set pin 8, 10, 11 and pin 12 to output mode. */ + value32 |= ((u4bTmp << 8) | 0x001D0000); + rtw_write32(padapter, REG_GPIO_PIN_CTRL_2, value32); + + /* 3. Disable LED0 & 1 */ + rtw_write16(padapter, REG_LEDCFG0, 0x8080); +} /* end of _DisableGPIO() */ + +static void _DisableRFAFEAndResetBB8192C(struct rtw_adapter *padapter) +{ +/************************************** +a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue +b. RF path 0 offset 0x00 = 0x00 disable RF +c. APSD_CTRL 0x600[7:0] = 0x40 +d. SYS_FUNC_EN 0x02[7:0] = 0x16 reset BB state machine +e. SYS_FUNC_EN 0x02[7:0] = 0x14 reset BB state machine +***************************************/ + u8 eRFPath = 0, value8 = 0; + + rtw_write8(padapter, REG_TXPAUSE, 0xFF); + + PHY_SetRFReg(padapter, (enum RF_RADIO_PATH) eRFPath, 0x0, bMaskByte0, 0x0); + + value8 |= APSDOFF; + rtw_write8(padapter, REG_APSD_CTRL, value8); /* 0x40 */ + + /* Set BB reset at first */ + value8 = 0; + value8 |= (FEN_USBD | FEN_USBA | FEN_BB_GLB_RSTn); + rtw_write8(padapter, REG_SYS_FUNC_EN, value8); /* 0x16 */ + + /* Set global reset. */ + value8 &= ~FEN_BB_GLB_RSTn; + rtw_write8(padapter, REG_SYS_FUNC_EN, value8); /* 0x14 */ + + /* 2010/08/12 MH We need to set BB/GLBAL reset to save power + for SS mode. */ + +/* RT_TRACE(COMP_INIT, DBG_LOUD, ("======> RF off and reset BB.\n")); */ +} + +static void _DisableRFAFEAndResetBB(struct rtw_adapter *padapter) +{ + _DisableRFAFEAndResetBB8192C(padapter); +} + +static void _ResetDigitalProcedure1_92C(struct rtw_adapter *padapter, + bool bWithoutHWSM) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (IS_FW_81xxC(padapter) && (pHalData->FirmwareVersion <= 0x20)) { + /***************************** + f. MCUFWDL 0x80[7:0]= 0 reset MCU ready status + g. SYS_FUNC_EN 0x02[10]= 0 reset MCU register, (8051 reset) + h. SYS_FUNC_EN 0x02[15-12]= 5 reset MAC register, DCORE + i. SYS_FUNC_EN 0x02[10]= 1 enable MCU register, + (8051 enable) + ******************************/ + u16 valu16 = 0; + rtw_write8(padapter, REG_MCUFWDL, 0); + + valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN); + /* reset MCU , 8051 */ + rtw_write16(padapter, REG_SYS_FUNC_EN, (valu16 & (~FEN_CPUEN))); + + valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN) & 0x0FFF; + rtw_write16(padapter, REG_SYS_FUNC_EN, + (valu16 | (FEN_HWPDN | FEN_ELDR))); /* reset MAC */ + + valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN); + /* enable MCU , 8051 */ + rtw_write16(padapter, REG_SYS_FUNC_EN, (valu16 | FEN_CPUEN)); + } else { + u8 retry_cnts = 0; + + /* 2010/08/12 MH For USB SS, we can not stop 8051 when we + are trying to enter IPS/HW&SW radio off. For + S3/S4/S5/Disable, we can stop 8051 because */ + /* we will init FW when power on again. */ + /* if (!pDevice->RegUsbSS) */ + /* If we want to SS mode, we can not reset 8051. */ + if (rtw_read8(padapter, REG_MCUFWDL) & BIT1) { + /* IF fw in RAM code, do reset */ + if (padapter->bFWReady) { + /* 2010/08/25 MH Accordign to RD alfred's + suggestion, we need to disable other */ + /* HRCV INT to influence 8051 reset. */ + rtw_write8(padapter, REG_FWIMR, 0x20); + /* 2011/02/15 MH According to Alex's + suggestion, close mask to prevent + incorrect FW write operation. */ + rtw_write8(padapter, REG_FTIMR, 0x00); + rtw_write8(padapter, REG_FSIMR, 0x00); + + /* 8051 reset by self */ + rtw_write8(padapter, REG_HMETFR + 3, 0x20); + + while ((retry_cnts++ < 100) && + (FEN_CPUEN & + rtw_read16(padapter, REG_SYS_FUNC_EN))) { + udelay(50); /* us */ + } + + if (retry_cnts >= 100) { + /* Reset MAC and Enable 8051 */ + rtw_write8(padapter, + REG_SYS_FUNC_EN + 1, 0x50); + mdelay(10); + } + } + } + /* Reset MAC and Enable 8051 */ + rtw_write8(padapter, REG_SYS_FUNC_EN + 1, 0x54); + rtw_write8(padapter, REG_MCUFWDL, 0); + } + + if (bWithoutHWSM) { + /***************************** + Without HW auto state machine + g. SYS_CLKR 0x08[15:0] = 0x30A3 disable MAC clock + h. AFE_PLL_CTRL 0x28[7:0] = 0x80 disable AFE PLL + i. AFE_XTAL_CTRL 0x24[15:0] = 0x880F gated AFE DIG_CLOCK + j. SYS_ISO_CTRL 0x00[7:0] = 0xF9 isolated digital to PON + ******************************/ + /* modify to 0x70A3 by Scott. */ + rtw_write16(padapter, REG_SYS_CLKR, 0x70A3); + rtw_write8(padapter, REG_AFE_PLL_CTRL, 0x80); + rtw_write16(padapter, REG_AFE_XTAL_CTRL, 0x880F); + rtw_write8(padapter, REG_SYS_ISO_CTRL, 0xF9); + } else { + /* Disable all RF/BB power */ + rtw_write8(padapter, REG_RF_CTRL, 0x00); + } +} + +static void _ResetDigitalProcedure1(struct rtw_adapter *padapter, + bool bWithoutHWSM) +{ + _ResetDigitalProcedure1_92C(padapter, bWithoutHWSM); +} + +static void _ResetDigitalProcedure2(struct rtw_adapter *padapter) +{ +/***************************** +k. SYS_FUNC_EN 0x03[7:0] = 0x44 disable ELDR runction +l. SYS_CLKR 0x08[15:0] = 0x3083 disable ELDR clock +m. SYS_ISO_CTRL 0x01[7:0] = 0x83 isolated ELDR to PON +******************************/ + /* modify to 0x70a3 by Scott. */ + rtw_write16(padapter, REG_SYS_CLKR, 0x70a3); + /* modify to 0x82 by Scott. */ + rtw_write8(padapter, REG_SYS_ISO_CTRL + 1, 0x82); +} + +static void _DisableAnalog(struct rtw_adapter *padapter, bool bWithoutHWSM) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u16 value16 = 0; + u8 value8 = 0; + + if (bWithoutHWSM) { + /***************************** + n. LDOA15_CTRL 0x20[7:0] = 0x04 disable A15 power + o. LDOV12D_CTRL 0x21[7:0] = 0x54 disable digital core power + r. When driver call disable, the ASIC will turn off remaining + clock automatically + ******************************/ + + rtw_write8(padapter, REG_LDOA15_CTRL, 0x04); + /* rtw_write8(padapter, REG_LDOV12D_CTRL, 0x54); */ + + value8 = rtw_read8(padapter, REG_LDOV12D_CTRL); + value8 &= (~LDV12_EN); + rtw_write8(padapter, REG_LDOV12D_CTRL, value8); +/* RT_TRACE(COMP_INIT, DBG_LOUD, + (" REG_LDOV12D_CTRL Reg0x21:0x%02x.\n", value8)); */ + } + + /***************************** + h. SPS0_CTRL 0x11[7:0] = 0x23 enter PFM mode + i. APS_FSMCO 0x04[15:0] = 0x4802 set USB suspend + ******************************/ + value8 = 0x23; + if (IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)) + value8 |= BIT3; + + rtw_write8(padapter, REG_SPS0_CTRL, value8); + + if (bWithoutHWSM) { + /* value16 |= (APDM_HOST | FSM_HSUS |/PFM_ALDN); */ + /* 2010/08/31 According to Filen description, we need to + use HW to shut down 8051 automatically. */ + /* Becasue suspend operatione need the asistance of 8051 + to wait for 3ms. */ + value16 |= (APDM_HOST | AFSM_HSUS | PFM_ALDN); + } else { + value16 |= (APDM_HOST | AFSM_HSUS | PFM_ALDN); + } + + rtw_write16(padapter, REG_APS_FSMCO, value16); /* 0x4802 */ + + rtw_write8(padapter, REG_RSV_CTRL, 0x0e); +} + +/* HW Auto state machine */ +s32 CardDisableHWSM(struct rtw_adapter *padapter, u8 resetMCU) +{ + int rtStatus = _SUCCESS; + + if (padapter->bSurpriseRemoved) { + return rtStatus; + } + /* RF Off Sequence ==== */ + _DisableRFAFEAndResetBB(padapter); + + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure1(padapter, false); + + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + _DisableGPIO(padapter); + + /* ==== Disable analog sequence === */ + _DisableAnalog(padapter, false); + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("======> Card disable finished.\n")); + + return rtStatus; +} + +/* without HW Auto state machine */ +s32 CardDisableWithoutHWSM(struct rtw_adapter *padapter) +{ + s32 rtStatus = _SUCCESS; + + /* RT_TRACE(COMP_INIT, DBG_LOUD, + ("======> Card Disable Without HWSM .\n")); */ + if (padapter->bSurpriseRemoved) { + return rtStatus; + } + + /* RF Off Sequence ==== */ + _DisableRFAFEAndResetBB(padapter); + + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure1(padapter, true); + + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + _DisableGPIO(padapter); + + /* ==== Reset digital sequence ====== */ + _ResetDigitalProcedure2(padapter); + + /* ==== Disable analog sequence === */ + _DisableAnalog(padapter, true); + + /* RT_TRACE(COMP_INIT, DBG_LOUD, + ("<====== Card Disable Without HWSM .\n")); */ + return rtStatus; +} + +void Hal_InitPGData(struct rtw_adapter *padapter, u8 *PROMContent) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); + + if (false == pEEPROM->bautoload_fail_flag) { /* autoload OK. */ + if (!pEEPROM->EepromOrEfuse) { + /* Read EFUSE real map to shadow. */ + EFUSE_ShadowMapUpdate23a(padapter, EFUSE_WIFI); + memcpy((void *)PROMContent, + (void *)pEEPROM->efuse_eeprom_data, + HWSET_MAX_SIZE); + } + } else { /* autoload fail */ + RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, + ("AutoLoad Fail reported from CR9346!!\n")); +/* pHalData->AutoloadFailFlag = true; */ + /* update to default value 0xFF */ + if (false == pEEPROM->EepromOrEfuse) + EFUSE_ShadowMapUpdate23a(padapter, EFUSE_WIFI); + memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data, + HWSET_MAX_SIZE); + } +} + +void Hal_EfuseParseIDCode(struct rtw_adapter *padapter, u8 *hwinfo) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); +/* struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); */ + u16 EEPROMId; + + /* Checl 0x8129 again for making sure autoload status!! */ + EEPROMId = le16_to_cpu(*((u16 *) hwinfo)); + if (EEPROMId != RTL_EEPROM_ID) { + DBG_8723A("EEPROM ID(%#x) is invalid!!\n", EEPROMId); + pEEPROM->bautoload_fail_flag = true; + } else { + pEEPROM->bautoload_fail_flag = false; + } + + RT_TRACE(_module_hal_init_c_, _drv_info_, + ("EEPROM ID = 0x%04x\n", EEPROMId)); +} + +static void Hal_EEValueCheck(u8 EEType, void *pInValue, void *pOutValue) +{ + switch (EEType) { + case EETYPE_TX_PWR: + { + u8 *pIn, *pOut; + pIn = (u8 *) pInValue; + pOut = (u8 *) pOutValue; + if (*pIn >= 0 && *pIn <= 63) { + *pOut = *pIn; + } else { + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, + ("EETYPE_TX_PWR, value =%d is invalid, set " + "to default = 0x%x\n", + *pIn, EEPROM_Default_TxPowerLevel)); + *pOut = EEPROM_Default_TxPowerLevel; + } + } + break; + default: + break; + } +} + +static void +Hal_ReadPowerValueFromPROM_8723A(struct txpowerinfo *pwrInfo, + u8 *PROMContent, bool AutoLoadFail) +{ + u32 rfPath, eeAddr, group, rfPathMax = 1; + + memset(pwrInfo, 0, sizeof(*pwrInfo)); + + if (AutoLoadFail) { + for (group = 0; group < MAX_CHNL_GROUP; group++) { + for (rfPath = 0; rfPath < rfPathMax; rfPath++) { + pwrInfo->CCKIndex[rfPath][group] = + EEPROM_Default_TxPowerLevel; + pwrInfo->HT40_1SIndex[rfPath][group] = + EEPROM_Default_TxPowerLevel; + pwrInfo->HT40_2SIndexDiff[rfPath][group] = + EEPROM_Default_HT40_2SDiff; + pwrInfo->HT20IndexDiff[rfPath][group] = + EEPROM_Default_HT20_Diff; + pwrInfo->OFDMIndexDiff[rfPath][group] = + EEPROM_Default_LegacyHTTxPowerDiff; + pwrInfo->HT40MaxOffset[rfPath][group] = + EEPROM_Default_HT40_PwrMaxOffset; + pwrInfo->HT20MaxOffset[rfPath][group] = + EEPROM_Default_HT20_PwrMaxOffset; + } + } + pwrInfo->TSSI_A[0] = EEPROM_Default_TSSI; + return; + } + + for (rfPath = 0; rfPath < rfPathMax; rfPath++) { + for (group = 0; group < MAX_CHNL_GROUP; group++) { + eeAddr = + EEPROM_CCK_TX_PWR_INX_8723A + (rfPath * 3) + group; + /* pwrInfo->CCKIndex[rfPath][group] = + PROMContent[eeAddr]; */ + Hal_EEValueCheck(EETYPE_TX_PWR, &PROMContent[eeAddr], + &pwrInfo->CCKIndex[rfPath][group]); + eeAddr = EEPROM_HT40_1S_TX_PWR_INX_8723A + + (rfPath * 3) + group; + /* pwrInfo->HT40_1SIndex[rfPath][group] = + PROMContent[eeAddr]; */ + Hal_EEValueCheck(EETYPE_TX_PWR, &PROMContent[eeAddr], + &pwrInfo->HT40_1SIndex[rfPath][group]); + } + } + + for (group = 0; group < MAX_CHNL_GROUP; group++) { + for (rfPath = 0; rfPath < rfPathMax; rfPath++) { + pwrInfo->HT40_2SIndexDiff[rfPath][group] = 0; + pwrInfo->HT20IndexDiff[rfPath][group] = + (PROMContent + [EEPROM_HT20_TX_PWR_INX_DIFF_8723A + + group] >> (rfPath * 4)) & 0xF; + /* 4bit sign number to 8 bit sign number */ + if (pwrInfo->HT20IndexDiff[rfPath][group] & BIT3) + pwrInfo->HT20IndexDiff[rfPath][group] |= 0xF0; + + pwrInfo->OFDMIndexDiff[rfPath][group] = + (PROMContent[EEPROM_OFDM_TX_PWR_INX_DIFF_8723A + + group] >> (rfPath * 4)) & 0xF; + + pwrInfo->HT40MaxOffset[rfPath][group] = + (PROMContent[EEPROM_HT40_MAX_PWR_OFFSET_8723A + + group] >> (rfPath * 4)) & 0xF; + + pwrInfo->HT20MaxOffset[rfPath][group] = + (PROMContent[EEPROM_HT20_MAX_PWR_OFFSET_8723A + + group] >> (rfPath * 4)) & 0xF; + } + } + + pwrInfo->TSSI_A[0] = PROMContent[EEPROM_TSSI_A_8723A]; +} + +static u8 Hal_GetChnlGroup(u8 chnl) +{ + u8 group = 0; + + if (chnl < 3) /* Cjanel 1-3 */ + group = 0; + else if (chnl < 9) /* Channel 4-9 */ + group = 1; + else /* Channel 10-14 */ + group = 2; + + return group; +} + +void +Hal_EfuseParsetxpowerinfo_8723A(struct rtw_adapter *padapter, + u8 *PROMContent, bool AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct txpowerinfo pwrInfo; + u8 rfPath, ch, group, rfPathMax = 1; + u8 pwr, diff; + + Hal_ReadPowerValueFromPROM_8723A(&pwrInfo, PROMContent, AutoLoadFail); + for (rfPath = 0; rfPath < rfPathMax; rfPath++) { + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + group = Hal_GetChnlGroup(ch); + + pHalData->TxPwrLevelCck[rfPath][ch] = + pwrInfo.CCKIndex[rfPath][group]; + pHalData->TxPwrLevelHT40_1S[rfPath][ch] = + pwrInfo.HT40_1SIndex[rfPath][group]; + + pHalData->TxPwrHt20Diff[rfPath][ch] = + pwrInfo.HT20IndexDiff[rfPath][group]; + pHalData->TxPwrLegacyHtDiff[rfPath][ch] = + pwrInfo.OFDMIndexDiff[rfPath][group]; + pHalData->PwrGroupHT20[rfPath][ch] = + pwrInfo.HT20MaxOffset[rfPath][group]; + pHalData->PwrGroupHT40[rfPath][ch] = + pwrInfo.HT40MaxOffset[rfPath][group]; + + pwr = pwrInfo.HT40_1SIndex[rfPath][group]; + diff = pwrInfo.HT40_2SIndexDiff[rfPath][group]; + + pHalData->TxPwrLevelHT40_2S[rfPath][ch] = + (pwr > diff) ? (pwr - diff) : 0; + } + } + for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) { + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("RF(%u)-Ch(%u) [CCK / HT40_1S / HT40_2S] = " + "[0x%x / 0x%x / 0x%x]\n", + rfPath, ch, + pHalData->TxPwrLevelCck[rfPath][ch], + pHalData->TxPwrLevelHT40_1S[rfPath][ch], + pHalData->TxPwrLevelHT40_2S[rfPath][ch])); + + } + } + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("RF-A Ht20 to HT40 Diff[%u] = 0x%x(%d)\n", ch, + pHalData->TxPwrHt20Diff[RF_PATH_A][ch], + pHalData->TxPwrHt20Diff[RF_PATH_A][ch])); + } + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("RF-A Legacy to Ht40 Diff[%u] = 0x%x\n", ch, + pHalData->TxPwrLegacyHtDiff[RF_PATH_A][ch])); + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("RF-B Ht20 to HT40 Diff[%u] = 0x%x(%d)\n", ch, + pHalData->TxPwrHt20Diff[RF_PATH_B][ch], + pHalData->TxPwrHt20Diff[RF_PATH_B][ch])); + } + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("RF-B Legacy to HT40 Diff[%u] = 0x%x\n", ch, + pHalData->TxPwrLegacyHtDiff[RF_PATH_B][ch])); + if (!AutoLoadFail) { + struct registry_priv *registry_par = &padapter->registrypriv; + if (registry_par->regulatory_tid == 0xff) { + if (PROMContent[RF_OPTION1_8723A] == 0xff) + pHalData->EEPROMRegulatory = 0; + else + pHalData->EEPROMRegulatory = + PROMContent[RF_OPTION1_8723A] & 0x7; + } else { + pHalData->EEPROMRegulatory = + registry_par->regulatory_tid; + } + } else { + pHalData->EEPROMRegulatory = 0; + } + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory)); + + if (!AutoLoadFail) + pHalData->bTXPowerDataReadFromEEPORM = true; +} + +void +Hal_EfuseParseBTCoexistInfo_8723A(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u8 tempval; + u32 tmpu4; + + if (!AutoLoadFail) { + tmpu4 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL); + if (tmpu4 & BT_FUNC_EN) + pHalData->EEPROMBluetoothCoexist = 1; + else + pHalData->EEPROMBluetoothCoexist = 0; + pHalData->EEPROMBluetoothType = BT_RTL8723A; + + /* The following need to be checked with newer version of */ + /* eeprom spec */ + tempval = hwinfo[RF_OPTION4_8723A]; + pHalData->EEPROMBluetoothAntNum = (tempval & 0x1); + pHalData->EEPROMBluetoothAntIsolation = ((tempval & 0x10) >> 4); + pHalData->EEPROMBluetoothRadioShared = ((tempval & 0x20) >> 5); + } else { + pHalData->EEPROMBluetoothCoexist = 0; + pHalData->EEPROMBluetoothType = BT_RTL8723A; + pHalData->EEPROMBluetoothAntNum = Ant_x2; + pHalData->EEPROMBluetoothAntIsolation = 0; + pHalData->EEPROMBluetoothRadioShared = BT_Radio_Shared; + } +#ifdef CONFIG_8723AU_BT_COEXIST + BT_InitHalVars(padapter); +#endif +} + +void +Hal_EfuseParseEEPROMVer(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!AutoLoadFail) + pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_8723A]; + else + pHalData->EEPROMVersion = 1; + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n", + pHalData->EEPROMVersion)); +} + +void +rtl8723a_EfuseParseChnlPlan(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ + padapter->mlmepriv.ChannelPlan = + hal_com_get_channel_plan23a(padapter, hwinfo ? + hwinfo[EEPROM_ChannelPlan_8723A]:0xFF, + padapter->registrypriv.channel_plan, + RT_CHANNEL_DOMAIN_WORLD_WIDE_13, + AutoLoadFail); + + DBG_8723A("mlmepriv.ChannelPlan = 0x%02x\n", + padapter->mlmepriv.ChannelPlan); +} + +void +Hal_EfuseParseCustomerID(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + if (!AutoLoadFail) { + pHalData->EEPROMCustomerID = hwinfo[EEPROM_CustomID_8723A]; + pHalData->EEPROMSubCustomerID = + hwinfo[EEPROM_SubCustomID_8723A]; + } else { + pHalData->EEPROMCustomerID = 0; + pHalData->EEPROMSubCustomerID = 0; + } + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID)); + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("EEPROM SubCustomer ID: 0x%02x\n", + pHalData->EEPROMSubCustomerID)); +} + +void +Hal_EfuseParseAntennaDiversity(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ +} + +void +Hal_EfuseParseRateIndicationOption(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ +} + +void +Hal_EfuseParseXtal_8723A(struct rtw_adapter *pAdapter, + u8 *hwinfo, u8 AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + + if (!AutoLoadFail) { + pHalData->CrystalCap = hwinfo[EEPROM_XTAL_K_8723A]; + if (pHalData->CrystalCap == 0xFF) + pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723A; + } else { + pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723A; + } + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("%s: CrystalCap = 0x%2x\n", __func__, + pHalData->CrystalCap)); +} + +void +Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter, + u8 *PROMContent, u8 AutoloadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + /* */ + /* ThermalMeter from EEPROM */ + /* */ + if (false == AutoloadFail) + pHalData->EEPROMThermalMeter = + PROMContent[EEPROM_THERMAL_METER_8723A]; + else + pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + + if ((pHalData->EEPROMThermalMeter == 0xff) || (true == AutoloadFail)) { + pHalData->bAPKThermalMeterIgnore = true; + pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + } + + DBG_8723A("%s: ThermalMeter = 0x%x\n", __func__, + pHalData->EEPROMThermalMeter); +} + +void Hal_InitChannelPlan23a(struct rtw_adapter *padapter) +{ +} + +static void rtl8723a_cal_txdesc_chksum(struct tx_desc *ptxdesc) +{ + u16 *usPtr = (u16 *) ptxdesc; + u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ + u32 index; + u16 checksum = 0; + + /* Clear first */ + ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); + + for (index = 0; index < count; index++) { + checksum ^= le16_to_cpu(*(usPtr + index)); + } + + ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); +} + +static void fill_txdesc_sectype(struct pkt_attrib *pattrib, + struct txdesc_8723a *ptxdesc) +{ + if ((pattrib->encrypt > 0) && !pattrib->bswenc) { + switch (pattrib->encrypt) { + /* SEC_TYPE */ + case _WEP40_: + case _WEP104_: + case _TKIP_: + case _TKIP_WTMIC_: + ptxdesc->sectype = 1; + break; + + case _AES_: + ptxdesc->sectype = 3; + break; + + case _NO_PRIVACY_: + default: + break; + } + } +} + +static void fill_txdesc_vcs(struct pkt_attrib *pattrib, + struct txdesc_8723a *ptxdesc) +{ + /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */ + + switch (pattrib->vcs_mode) { + case RTS_CTS: + ptxdesc->rtsen = 1; + break; + + case CTS_TO_SELF: + ptxdesc->cts2self = 1; + break; + + case NONE_VCS: + default: + break; + } + + if (pattrib->vcs_mode) { + ptxdesc->hw_rts_en = 1; /* ENABLE HW RTS */ + + /* Set RTS BW */ + if (pattrib->ht_en) { + if (pattrib->bwmode & HT_CHANNEL_WIDTH_40) + ptxdesc->rts_bw = 1; + + switch (pattrib->ch_offset) { + case HAL_PRIME_CHNL_OFFSET_DONT_CARE: + ptxdesc->rts_sc = 0; + break; + + case HAL_PRIME_CHNL_OFFSET_LOWER: + ptxdesc->rts_sc = 1; + break; + + case HAL_PRIME_CHNL_OFFSET_UPPER: + ptxdesc->rts_sc = 2; + break; + + default: + ptxdesc->rts_sc = 3; /* Duplicate */ + break; + } + } + } +} + +static void fill_txdesc_phy(struct pkt_attrib *pattrib, + struct txdesc_8723a *ptxdesc) +{ + if (pattrib->ht_en) { + if (pattrib->bwmode & HT_CHANNEL_WIDTH_40) + ptxdesc->data_bw = 1; + + switch (pattrib->ch_offset) { + case HAL_PRIME_CHNL_OFFSET_DONT_CARE: + ptxdesc->data_sc = 0; + break; + + case HAL_PRIME_CHNL_OFFSET_LOWER: + ptxdesc->data_sc = 1; + break; + + case HAL_PRIME_CHNL_OFFSET_UPPER: + ptxdesc->data_sc = 2; + break; + + default: + ptxdesc->data_sc = 3; /* Duplicate */ + break; + } + } +} + +static void rtl8723a_fill_default_txdesc(struct xmit_frame *pxmitframe, + u8 *pbuf) +{ + struct rtw_adapter *padapter; + struct hal_data_8723a *pHalData; + struct dm_priv *pdmpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + struct pkt_attrib *pattrib; + struct txdesc_8723a *ptxdesc; + s32 bmcst; + + padapter = pxmitframe->padapter; + pHalData = GET_HAL_DATA(padapter); + pdmpriv = &pHalData->dmpriv; + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + pattrib = &pxmitframe->attrib; + bmcst = is_multicast_ether_addr(pattrib->ra); + + ptxdesc = (struct txdesc_8723a *)pbuf; + + if (pxmitframe->frame_tag == DATA_FRAMETAG) { + ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ + + if (pattrib->ampdu_en == true) + ptxdesc->agg_en = 1; /* AGG EN */ + else + ptxdesc->bk = 1; /* AGG BK */ + + ptxdesc->qsel = pattrib->qsel; + ptxdesc->rate_id = pattrib->raid; + + fill_txdesc_sectype(pattrib, ptxdesc); + + ptxdesc->seq = pattrib->seqnum; + + if ((pattrib->ether_type != 0x888e) && + (pattrib->ether_type != 0x0806) && + (pattrib->dhcp_pkt != 1)) { + /* Non EAP & ARP & DHCP type data packet */ + + fill_txdesc_vcs(pattrib, ptxdesc); + fill_txdesc_phy(pattrib, ptxdesc); + + ptxdesc->rtsrate = 8; /* RTS Rate = 24M */ + ptxdesc->data_ratefb_lmt = 0x1F; + ptxdesc->rts_ratefb_lmt = 0xF; + + /* use REG_INIDATA_RATE_SEL value */ + ptxdesc->datarate = + pdmpriv->INIDATA_RATE[pattrib->mac_id]; + + } else { + /* EAP data packet and ARP packet. */ + /* Use the 1M data rate to send the EAP/ARP packet. */ + /* This will maybe make the handshake smooth. */ + + ptxdesc->bk = 1; /* AGG BK */ + ptxdesc->userate = 1; /* driver uses rate */ + if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) + ptxdesc->data_short = 1; + ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate); + } + } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { +/* RT_TRACE(_module_hal_xmit_c_, _drv_notice_, + ("%s: MGNT_FRAMETAG\n", __func__)); */ + + ptxdesc->macid = pattrib->mac_id; /* CAM_ID(MAC_ID) */ + ptxdesc->qsel = pattrib->qsel; + ptxdesc->rate_id = pattrib->raid; /* Rate ID */ + ptxdesc->seq = pattrib->seqnum; + ptxdesc->userate = 1; /* driver uses rate, 1M */ + ptxdesc->rty_lmt_en = 1; /* retry limit enable */ + ptxdesc->data_rt_lmt = 6; /* retry limit = 6 */ + + /* CCX-TXRPT ack for xmit mgmt frames. */ + if (pxmitframe->ack_report) + ptxdesc->ccx = 1; + + ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate); + } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { + RT_TRACE(_module_hal_xmit_c_, _drv_warning_, + ("%s: TXAGG_FRAMETAG\n", __func__)); + } else { + RT_TRACE(_module_hal_xmit_c_, _drv_warning_, + ("%s: frame_tag = 0x%x\n", __func__, + pxmitframe->frame_tag)); + + ptxdesc->macid = 4; /* CAM_ID(MAC_ID) */ + ptxdesc->rate_id = 6; /* Rate ID */ + ptxdesc->seq = pattrib->seqnum; + ptxdesc->userate = 1; /* driver uses rate */ + ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate); + } + + ptxdesc->pktlen = pattrib->last_txcmdsz; + ptxdesc->offset = TXDESC_SIZE + OFFSET_SZ; + if (bmcst) + ptxdesc->bmc = 1; + ptxdesc->ls = 1; + ptxdesc->fs = 1; + ptxdesc->own = 1; + + /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */ + /* (1) The sequence number of each non-Qos frame / broadcast / + * multicast / mgnt frame should be controled by Hw because Fw + * will also send null data which we cannot control when Fw LPS enable. + * --> default enable non-Qos data sequense number. + 2010.06.23. by tynli. */ + /* (2) Enable HW SEQ control for beacon packet, + * because we use Hw beacon. */ + /* (3) Use HW Qos SEQ to control the seq num of Ext port + * non-Qos packets. */ + /* 2010.06.23. Added by tynli. */ + if (!pattrib->qos_en) { + /* Hw set sequence number */ + ptxdesc->hwseq_en = 1; /* HWSEQ_EN */ + ptxdesc->hwseq_sel = 0; /* HWSEQ_SEL */ + } +} + +/* + * Description: + * + * Parameters: + * pxmitframe xmitframe + * pbuf where to fill tx desc + */ +void rtl8723a_update_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf) +{ + struct tx_desc *pdesc; + + pdesc = (struct tx_desc *)pbuf; + memset(pdesc, 0, sizeof(struct tx_desc)); + + rtl8723a_fill_default_txdesc(pxmitframe, pbuf); + + pdesc->txdw0 = cpu_to_le32(pdesc->txdw0); + pdesc->txdw1 = cpu_to_le32(pdesc->txdw1); + pdesc->txdw2 = cpu_to_le32(pdesc->txdw2); + pdesc->txdw3 = cpu_to_le32(pdesc->txdw3); + pdesc->txdw4 = cpu_to_le32(pdesc->txdw4); + pdesc->txdw5 = cpu_to_le32(pdesc->txdw5); + pdesc->txdw6 = cpu_to_le32(pdesc->txdw6); + pdesc->txdw7 = cpu_to_le32(pdesc->txdw7); + rtl8723a_cal_txdesc_chksum(pdesc); +} + +/* + * Description: In normal chip, we should send some packet to Hw which + * will be used by Fw in FW LPS mode. The function is to fill the Tx + * descriptor of this packets, then + */ +/* Fw can tell Hw to send these packet derectly. */ +/* Added by tynli. 2009.10.15. */ +/* */ +void rtl8723a_fill_fake_txdesc(struct rtw_adapter *padapter, u8 *pDesc, + u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull) +{ + struct tx_desc *ptxdesc; + + /* Clear all status */ + ptxdesc = (struct tx_desc *)pDesc; + memset(pDesc, 0, TXDESC_SIZE); + + /* offset 0 */ + /* own, bFirstSeg, bLastSeg; */ + ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + + /* 32 bytes for TX Desc */ + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << + OFFSET_SHT) & 0x00ff0000); + + /* Buffer size + command header */ + ptxdesc->txdw0 |= cpu_to_le32(BufferLen & 0x0000ffff); + + /* offset 4 */ + /* Fixed queue of Mgnt queue */ + ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT << QSEL_SHT) & 0x00001f00); + + /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed + to error vlaue by Hw. */ + if (IsPsPoll) { + ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR); + } else { + /* Hw set sequence number */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); + /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */ + ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); + } + + if (true == IsBTQosNull) { + ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /* BT NULL */ + } + + /* offset 16 */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(8)); /* driver uses rate */ + + /* USB interface drop packet if the checksum of descriptor isn't + correct. */ + /* Using this checksum can let hardware recovery from packet bulk + out error (e.g. Cancel URC, Bulk out error.). */ + rtl8723a_cal_txdesc_chksum(ptxdesc); +} + +static void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode) +{ + u8 val8; + + if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { + StopTxBeacon(padapter); + + /* disable atim wnd */ + val8 = DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_ATIM; + SetBcnCtrlReg23a(padapter, val8, ~val8); + } else if ((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_) */) { + ResumeTxBeacon(padapter); + + val8 = DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB; + SetBcnCtrlReg23a(padapter, val8, ~val8); + } else if (mode == _HW_STATE_AP_) { +#ifdef CONFIG_8723AU_BT_COEXIST + /* add NULL Data and BT NULL Data Packets to FW RSVD Page */ + rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(padapter); +#endif + + ResumeTxBeacon(padapter); + + val8 = DIS_TSF_UDT | DIS_BCNQ_SUB; + SetBcnCtrlReg23a(padapter, val8, ~val8); + + /* Set RCR */ + /* rtw_write32(padapter, REG_RCR, 0x70002a8e); + CBSSID_DATA must set to 0 */ + /* CBSSID_DATA must set to 0 */ + rtw_write32(padapter, REG_RCR, 0x7000228e); + /* enable to rx data frame */ + rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); + /* enable to rx ps-poll */ + rtw_write16(padapter, REG_RXFLTMAP1, 0x0400); + + /* Beacon Control related register for first time */ + rtw_write8(padapter, REG_BCNDMATIM, 0x02); /* 2ms */ + rtw_write8(padapter, REG_DRVERLYINT, 0x05); /* 5ms */ + rtw_write8(padapter, REG_ATIMWND, 0x0a); /* 10ms for port0 */ + rtw_write16(padapter, REG_BCNTCFG, 0x00); + rtw_write16(padapter, REG_TBTT_PROHIBIT, 0xff04); + /* +32767 (~32ms) */ + rtw_write16(padapter, REG_TSFTR_SYN_OFFSET, 0x7fff); + + /* reset TSF */ + rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0)); + + /* enable BCN Function */ + /* don't enable update TSF (due to TSF update when + beacon/probe rsp are received) */ + val8 = DIS_TSF_UDT | EN_BCN_FUNCTION | + EN_TXBCN_RPT | DIS_BCNQ_SUB; + SetBcnCtrlReg23a(padapter, val8, ~val8); + } + + val8 = rtw_read8(padapter, MSR); + val8 = (val8 & 0xC) | mode; + rtw_write8(padapter, MSR, val8); +} + +static void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val) +{ + u8 idx = 0; + u32 reg_macid; + + reg_macid = REG_MACID; + + for (idx = 0; idx < 6; idx++) + rtw_write8(padapter, (reg_macid + idx), val[idx]); +} + +static void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val) +{ + u8 idx = 0; + u32 reg_bssid; + + reg_bssid = REG_BSSID; + + for (idx = 0; idx < 6; idx++) + rtw_write8(padapter, (reg_bssid + idx), val[idx]); +} + +static void hw_var_set_correct_tsf(struct rtw_adapter *padapter) +{ + u64 tsf; + u32 reg_tsftr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + /* tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue % + (pmlmeinfo->bcn_interval*1024)) - 1024; us */ + tsf = pmlmeext->TSFValue - + rtw_modular6423a(pmlmeext->TSFValue, + (pmlmeinfo->bcn_interval * 1024)) - 1024; /* us */ + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + /* pHalData->RegTxPause |= STOP_BCNQ;BIT(6) */ + /* rtw_write8(padapter, REG_TXPAUSE, + (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); */ + StopTxBeacon(padapter); + } + + reg_tsftr = REG_TSFTR; + + /* disable related TSF function */ + SetBcnCtrlReg23a(padapter, 0, EN_BCN_FUNCTION); + + rtw_write32(padapter, reg_tsftr, tsf); + rtw_write32(padapter, reg_tsftr + 4, tsf >> 32); + + /* enable related TSF function */ + SetBcnCtrlReg23a(padapter, EN_BCN_FUNCTION, 0); + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + ResumeTxBeacon(padapter); +} + +static void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter) +{ + /* reject all data frames */ + rtw_write16(padapter, REG_RXFLTMAP2, 0); + + /* reset TSF */ + rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0)); + + /* disable update TSF */ + SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0); +} + +static void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type) +{ + u8 RetryLimit = 0x30; + + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (type == 0) { /* prepare to join */ + u32 v32; + + /* enable to rx data frame.Accept all data frame */ + /* rtw_write32(padapter, REG_RCR, + rtw_read32(padapter, REG_RCR)|RCR_ADF); */ + rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF); + + v32 = rtw_read32(padapter, REG_RCR); + v32 |= RCR_CBSSID_DATA | RCR_CBSSID_BCN; + rtw_write32(padapter, REG_RCR, v32); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) + RetryLimit = + (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48; + else /* Ad-hoc Mode */ + RetryLimit = 0x7; + } else if (type == 1) { /* joinbss_event callback when join res < 0 */ + /* config RCR to receive different BSSID & not to + receive data frame during linking */ + rtw_write16(padapter, REG_RXFLTMAP2, 0); + } else if (type == 2) { /* sta add event callback */ + /* enable update TSF */ + SetBcnCtrlReg23a(padapter, 0, DIS_TSF_UDT); + + if (check_fwstate(pmlmepriv, + WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { + /* fixed beacon issue for 8191su........... */ + rtw_write8(padapter, 0x542, 0x02); + RetryLimit = 0x7; + } + } + + rtw_write16(padapter, REG_RL, + RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << + RETRY_LIMIT_LONG_SHIFT); + +#ifdef CONFIG_8723AU_BT_COEXIST + switch (type) { + case 0: + /* prepare to join */ + BT_WifiAssociateNotify(padapter, true); + break; + case 1: + /* joinbss_event callback when join res < 0 */ + BT_WifiAssociateNotify(padapter, false); + break; + case 2: + /* sta add event callback */ +/* BT_WifiMediaStatusNotify(padapter, RT_MEDIA_CONNECT); */ + break; + } +#endif +} + +void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + u32 *val32 = (u32 *)val; + + switch (variable) { + case HW_VAR_MEDIA_STATUS: + rtl8723a_set_media_status(padapter, *val); + break; + + case HW_VAR_MEDIA_STATUS1: + rtl8723a_set_media_status1(padapter, *val); + break; + + case HW_VAR_SET_OPMODE: + hw_var_set_opmode(padapter, *val); + break; + + case HW_VAR_MAC_ADDR: + hw_var_set_macaddr(padapter, val); + break; + + case HW_VAR_BSSID: + hw_var_set_bssid(padapter, val); + break; + + case HW_VAR_BASIC_RATE: + HalSetBrateCfg23a(padapter, val); + break; + + case HW_VAR_TXPAUSE: + rtl8723a_set_tx_pause(padapter, *val); + break; + + case HW_VAR_BCN_FUNC: + rtl8723a_set_bcn_func(padapter, *val); + break; + + case HW_VAR_CORRECT_TSF: + hw_var_set_correct_tsf(padapter); + break; + + case HW_VAR_CHECK_BSSID: + rtl8723a_check_bssid(padapter, *val); + break; + + case HW_VAR_MLME_DISCONNECT: + hw_var_set_mlme_disconnect(padapter); + break; + + case HW_VAR_MLME_SITESURVEY: + rtl8723a_mlme_sitesurvey(padapter, *val); + break; + + case HW_VAR_MLME_JOIN: + hw_var_set_mlme_join(padapter, *val); + break; + + case HW_VAR_ON_RCR_AM: + rtl8723a_on_rcr_am(padapter); + break; + + case HW_VAR_OFF_RCR_AM: + rtl8723a_off_rcr_am(padapter); + break; + + case HW_VAR_BEACON_INTERVAL: + rtl8723a_set_beacon_interval(padapter, *((u16 *) val)); + break; + + case HW_VAR_SLOT_TIME: + rtl8723a_set_slot_time(padapter, *val); + break; + + case HW_VAR_RESP_SIFS: + rtl8723a_set_resp_sifs(padapter, val[0], val[1], + val[2], val[3]); + break; + + case HW_VAR_ACK_PREAMBLE: + rtl8723a_ack_preamble(padapter, *val); + break; + + case HW_VAR_SEC_CFG: + rtl8723a_set_sec_cfg(padapter, *val); + break; + + case HW_VAR_DM_FLAG: + rtl8723a_odm_support_ability_write(padapter, *val32); + break; + case HW_VAR_DM_FUNC_OP: + rtl8723a_odm_support_ability_backup(padapter, *val); + break; + case HW_VAR_DM_FUNC_SET: + rtl8723a_odm_support_ability_set(padapter, *val32); + break; + + case HW_VAR_DM_FUNC_CLR: + rtl8723a_odm_support_ability_clr(padapter, *val32); + break; + + case HW_VAR_CAM_EMPTY_ENTRY: + rtl8723a_cam_empty_entry(padapter, *val); + break; + + case HW_VAR_CAM_INVALID_ALL: + rtl8723a_cam_invalid_all(padapter); + break; + + case HW_VAR_CAM_WRITE: + rtl8723a_cam_write(padapter, val32[0], val32[1]); + break; + + case HW_VAR_AC_PARAM_VO: + rtl8723a_set_ac_param_vo(padapter, *val32); + break; + + case HW_VAR_AC_PARAM_VI: + rtl8723a_set_ac_param_vi(padapter, *val32); + break; + + case HW_VAR_AC_PARAM_BE: + rtl8723a_set_ac_param_be(padapter, *val32); + break; + + case HW_VAR_AC_PARAM_BK: + rtl8723a_set_ac_param_bk(padapter, *val32); + break; + + case HW_VAR_ACM_CTRL: + rtl8723a_set_acm_ctrl(padapter, *val); + break; + + case HW_VAR_AMPDU_MIN_SPACE: + rtl8723a_set_ampdu_min_space(padapter, *val); + break; + + case HW_VAR_AMPDU_FACTOR: + rtl8723a_set_ampdu_factor(padapter, *val); + break; + + case HW_VAR_RXDMA_AGG_PG_TH: + rtl8723a_set_rxdma_agg_pg_th(padapter, *val); + break; + + case HW_VAR_H2C_FW_PWRMODE: + rtl8723a_set_FwPwrMode_cmd(padapter, *val); + break; + + case HW_VAR_H2C_FW_JOINBSSRPT: + rtl8723a_set_FwJoinBssReport_cmd(padapter, *val); + break; + +#ifdef CONFIG_8723AU_P2P + case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: + rtl8723a_set_p2p_ps_offload_cmd(padapter, *val); + break; +#endif /* CONFIG_8723AU_P2P */ + + case HW_VAR_INITIAL_GAIN: + rtl8723a_set_initial_gain(padapter, *val32); + break; + case HW_VAR_EFUSE_BYTES: + pHalData->EfuseUsedBytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_BT_BYTES: + pHalData->BTEfuseUsedBytes = *((u16 *) val); + break; + case HW_VAR_FIFO_CLEARN_UP: + rtl8723a_fifo_cleanup(padapter); + break; + case HW_VAR_CHECK_TXBUF: + break; + case HW_VAR_APFM_ON_MAC: + rtl8723a_set_apfm_on_mac(padapter, *val); + break; + + case HW_VAR_NAV_UPPER: + rtl8723a_set_nav_upper(padapter, *val32); + break; + case HW_VAR_BCN_VALID: + rtl8723a_bcn_valid(padapter); + break; + default: + break; + } + +} + +void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + + switch (variable) { + case HW_VAR_BASIC_RATE: + *((u16 *) val) = pHalData->BasicRateSet; + break; + + case HW_VAR_TXPAUSE: + *val = rtw_read8(padapter, REG_TXPAUSE); + break; + + case HW_VAR_BCN_VALID: + /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */ + val[0] = (BIT0 & rtw_read8(padapter, REG_TDECTRL + 2)) ? true : + false; + break; + + case HW_VAR_RF_TYPE: + *val = pHalData->rf_type; + break; + + case HW_VAR_DM_FLAG: + { + struct dm_odm_t *podmpriv = &pHalData->odmpriv; + *((u32 *) val) = podmpriv->SupportAbility; + } + break; + + case HW_VAR_FWLPS_RF_ON: + { + /* When we halt NIC, we should check if FW LPS is leave. */ + u32 valRCR; + + if ((padapter->bSurpriseRemoved == true) || + (padapter->pwrctrlpriv.rf_pwrstate == rf_off)) { + /* If it is in HW/SW Radio OFF or IPS state, we do + not check Fw LPS Leave, because Fw is unload. */ + *val = true; + } else { + valRCR = rtw_read32(padapter, REG_RCR); + valRCR &= 0x00070000; + if (valRCR) + *val = false; + else + *val = true; + } + } + break; + case HW_VAR_EFUSE_BYTES: + *((u16 *) val) = pHalData->EfuseUsedBytes; + break; + + case HW_VAR_EFUSE_BT_BYTES: + *((u16 *) val) = pHalData->BTEfuseUsedBytes; + break; + + case HW_VAR_APFM_ON_MAC: + *val = pHalData->bMacPwrCtrlOn; + break; + case HW_VAR_CHK_HI_QUEUE_EMPTY: + *val = + ((rtw_read32(padapter, REG_HGQ_INFORMATION) & 0x0000ff00) == + 0) ? true : false; + break; + } +} + +#ifdef CONFIG_8723AU_BT_COEXIST + +void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData; + struct dm_odm_t *pDM_Odm; + struct sw_ant_sw *pDM_SWAT_Table; + u8 i; + + pHalData = GET_HAL_DATA(padapter); + pDM_Odm = &pHalData->odmpriv; + pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + /* */ + /* RTL8723A Single and Dual antenna dynamic detection + mechanism when RF power state is on. */ + /* We should take power tracking, IQK, LCK, RCK RF read/write + operation into consideration. */ + /* 2011.12.15. */ + /* */ + if (!pHalData->bAntennaDetected) { + u8 btAntNum = BT_GetPGAntNum(padapter); + + /* Set default antenna B status */ + if (btAntNum == Ant_x2) + pDM_SWAT_Table->ANTB_ON = true; + else if (btAntNum == Ant_x1) + pDM_SWAT_Table->ANTB_ON = false; + else + pDM_SWAT_Table->ANTB_ON = true; + + if (pHalData->CustomerID != RT_CID_TOSHIBA) { + for (i = 0; i < MAX_ANTENNA_DETECTION_CNT; i++) { + if (ODM_SingleDualAntennaDetection + (&pHalData->odmpriv, ANTTESTALL) == true) + break; + } + + /* Set default antenna number for BT coexistence */ + if (btAntNum == Ant_x2) + BT_SetBtCoexCurrAntNum(padapter, + pDM_SWAT_Table-> + ANTB_ON ? 2 : 1); + } + pHalData->bAntennaDetected = true; + } +} +#endif /* CONFIG_8723AU_BT_COEXIST */ + +void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter, + struct rtw_adapter *src_adapter) +{ + memcpy(dst_adapter->HalData, src_adapter->HalData, + dst_adapter->hal_data_sz); +} + +void rtl8723a_start_thread(struct rtw_adapter *padapter) +{ +} + +void rtl8723a_stop_thread(struct rtw_adapter *padapter) +{ +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c new file mode 100644 index 000000000000..bac3f3bd5311 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c @@ -0,0 +1,1197 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8723A_PHYCFG_C_ + +#include +#include + +#include + +/*---------------------------Define Local Constant---------------------------*/ +/* Channel switch:The size of command tables for switch channel*/ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +/*---------------------------Define Local Constant---------------------------*/ + +/*------------------------Define global variable-----------------------------*/ + +/*------------------------Define local variable------------------------------*/ + +/*--------------------Define export function prototype-----------------------*/ +/* Please refer to header file */ +/*--------------------Define export function prototype-----------------------*/ + +/*----------------------------Function Body----------------------------------*/ +/* */ +/* 1. BB register R/W API */ +/* */ + +/** +* Function: phy_CalculateBitShift +* +* OverView: Get shifted position of the BitMask +* +* Input: +* u32 BitMask, +* +* Output: none +* Return: u32 Return the shift bit bit position of the mask +*/ +static u32 phy_CalculateBitShift(u32 BitMask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((BitMask>>i) & 0x1) == 1) + break; + } + + return i; +} + +/** +* Function: PHY_QueryBBReg +* +* OverView: Read "sepcific bits" from BB register +* +* Input: +* struct rtw_adapter * Adapter, +* u32 RegAddr, Target address to be readback +* u32 BitMask Target bit position in the +* target address to be readback +* Output: +* None +* Return: +* u32 Data The readback register value +* Note: +* This function is equal to "GetRegSetting" in PHY programming guide +*/ +u32 +PHY_QueryBBReg(struct rtw_adapter *Adapter, u32 RegAddr, u32 BitMask) +{ + u32 ReturnValue = 0, OriginalValue, BitShift; + + OriginalValue = rtw_read32(Adapter, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + ReturnValue = (OriginalValue & BitMask) >> BitShift; + return ReturnValue; +} + +/** +* Function: PHY_SetBBReg +* +* OverView: Write "Specific bits" to BB register (page 8~) +* +* Input: +* struct rtw_adapter * Adapter, +* u32 RegAddr, Target address to be modified +* u32 BitMask Target bit position in the +* target address to be modified +* u32 Data The new register value in the +* target bit position of the +* target address +* +* Output: +* None +* Return: +* None +* Note: +* This function is equal to "PutRegSetting" in PHY programming guide +*/ + +void +PHY_SetBBReg(struct rtw_adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) +{ + u32 OriginalValue, BitShift; + + /* RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); */ + + if (BitMask != bMaskDWord) {/* if not "double word" write */ + OriginalValue = rtw_read32(Adapter, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + Data = ((OriginalValue & (~BitMask)) | (Data << BitShift)); + } + + rtw_write32(Adapter, RegAddr, Data); + + /* RTPRINT(FPHY, PHY_BBW, ("BBW MASK = 0x%lx Addr[0x%lx]= 0x%lx\n", BitMask, RegAddr, Data)); */ + /* RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); */ +} + +/* */ +/* 2. RF register R/W API */ +/* */ + +/** +* Function: phy_RFSerialRead +* +* OverView: Read regster from RF chips +* +* Input: +* struct rtw_adapter * Adapter, +* enum RF_RADIO_PATH eRFPath, Radio path of A/B/C/D +* u32 Offset, The target address to be read +* +* Output: None +* Return: u32 reback value +* Note: Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and +* RFLSSIRead() +*/ +static u32 +phy_RFSerialRead(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath, + u32 Offset) +{ + u32 retValue = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct bb_reg_define *pPhyReg = &pHalData->PHYRegDef[eRFPath]; + u32 NewOffset; + u32 tmplong, tmplong2; + u8 RfPiEnable = 0; + /* */ + /* Make sure RF register offset is correct */ + /* */ + Offset &= 0x3f; + + /* */ + /* Switch page for 8256 RF IC */ + /* */ + NewOffset = Offset; + + /* 2009/06/17 MH We can not execute IO for power save or + other accident mode. */ + /* if (RT_CANNOT_IO(Adapter)) */ + /* */ + /* RTPRINT(FPHY, PHY_RFR, ("phy_RFSerialRead return all one\n")); */ + /* return 0xFFFFFFFF; */ + /* */ + + /* For 92S LSSI Read RFLSSIRead */ + /* For RF A/B write 0x824/82c(does not work in the future) */ + /* We must use 0x824 for RF A and B to execute read trigger */ + tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord); + if (eRFPath == RF_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, + bMaskDWord); + + tmplong2 = (tmplong2 & ~bLSSIReadAddress) | + (NewOffset << 23) | bLSSIReadEdge; /* T65 RF */ + + PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, + bMaskDWord, tmplong & (~bLSSIReadEdge)); + udelay(10);/* PlatformStallExecution(10); */ + + PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2); + udelay(100);/* PlatformStallExecution(100); */ + + PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, + tmplong | bLSSIReadEdge); + udelay(10);/* PlatformStallExecution(10); */ + + if (eRFPath == RF_PATH_A) + RfPiEnable = (u8)PHY_QueryBBReg(Adapter, + rFPGA0_XA_HSSIParameter1, BIT8); + else if (eRFPath == RF_PATH_B) + RfPiEnable = (u8)PHY_QueryBBReg(Adapter, + rFPGA0_XB_HSSIParameter1, BIT8); + + if (RfPiEnable) { + /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */ + retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, + bLSSIReadBackData); + /* DBG_8723A("Readback from RF-PI : 0x%x\n", retValue); */ + } else { + /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */ + retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, + bLSSIReadBackData); + /* DBG_8723A("Readback from RF-SI : 0x%x\n", retValue); */ + } + /* DBG_8723A("RFR-%d Addr[0x%x]= 0x%x\n", eRFPath, pPhyReg->rfLSSIReadBack, retValue); */ + + return retValue; +} + +/** +* Function: phy_RFSerialWrite +* +* OverView: Write data to RF register (page 8~) +* +* Input: +* struct rtw_adapter * Adapter, +* enum RF_RADIO_PATH eRFPath, Radio path of A/B/C/D +* u32 Offset, The target address to be read +* u32 Data The new register Data in the target +* bit position of the target to be read +* +* Output: +* None +* Return: +* None +* Note: +* Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and +* RFLSSIRead() +* +* Note: For RF8256 only +* The total count of RTL8256(Zebra4) register is around 36 bit it only employs +* 4-bit RF address. RTL8256 uses "register mode control bit" +* (Reg00[12], Reg00[10]) to access register address bigger than 0xf. +* See "Appendix-4 in PHY Configuration programming guide" for more details. +* Thus, we define a sub-finction for RTL8526 register address conversion +* =========================================================== +* Register Mode: RegCTL[1] RegCTL[0] Note +* (Reg00[12]) (Reg00[10]) +* =========================================================== +* Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) +* ------------------------------------------------------------------ +* Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) +* ------------------------------------------------------------------ +* Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) +* ------------------------------------------------------------------ +* +* 2008/09/02 MH Add 92S RF definition +*/ +static void +phy_RFSerialWrite(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath, + u32 Offset, u32 Data) +{ + u32 DataAndAddr = 0; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct bb_reg_define *pPhyReg = &pHalData->PHYRegDef[eRFPath]; + u32 NewOffset; + + /* 2009/06/17 MH We can not execute IO for power save or + other accident mode. */ + /* if (RT_CANNOT_IO(Adapter)) */ + /* */ + /* RTPRINT(FPHY, PHY_RFW, ("phy_RFSerialWrite stop\n")); */ + /* return; */ + /* */ + + Offset &= 0x3f; + + /* */ + /* Shadow Update */ + /* */ + /* PHY_RFShadowWrite(Adapter, eRFPath, Offset, Data); */ + + /* */ + /* Switch page for 8256 RF IC */ + /* */ + NewOffset = Offset; + + /* */ + /* Put write addr in [5:0] and write data in [31:16] */ + /* */ + /* DataAndAddr = (Data<<16) | (NewOffset&0x3f); */ + /* T65 RF */ + DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; + + /* */ + /* Write Operation */ + /* */ + PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + /* RTPRINT(FPHY, PHY_RFW, ("RFW-%d Addr[0x%lx]= 0x%lx\n", eRFPath, pPhyReg->rf3wireOffset, DataAndAddr)); */ + +} + +/** +* Function: PHY_QueryRFReg +* +* OverView: Query "Specific bits" to RF register (page 8~) +* +* Input: +* struct rtw_adapter * Adapter, +* enum RF_RADIO_PATH eRFPath, Radio path of A/B/C/D +* u32 RegAddr, The target address to be read +* u32BitMask The target bit position in the target +* address to be read +* +* Output: +* None +* Return: +* u32 Readback value +* Note: +* This function is equal to "GetRFRegSetting" in PHY programming guide +*/ +u32 +PHY_QueryRFReg(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath, + u32 RegAddr, u32 BitMask) +{ + u32 Original_Value, Readback_Value, BitShift; + /* struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); */ + /* u8 RFWaitCounter = 0; */ + /* _irqL irqL; */ + + Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); + + BitShift = phy_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + + return Readback_Value; +} + +/** +* Function: PHY_SetRFReg +* +* OverView: Write "Specific bits" to RF register (page 8~) +* +* Input: +* struct rtw_adapter * Adapter, +* enum RF_RADIO_PATH eRFPath, Radio path of A/B/C/D +* u32 RegAddr, The target address to be modified +* u32 BitMask The target bit position in the target +* address to be modified +* u32 Data The new register Data in the target +* bit position of the target address +* +* Output: +* None +* Return: +* None +* Note: This function is equal to "PutRFRegSetting" in PHY programming guide +*/ +void +PHY_SetRFReg(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath, + u32 RegAddr, u32 BitMask, u32 Data) +{ + /* struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); */ + /* u8 RFWaitCounter = 0; */ + u32 Original_Value, BitShift; + + /* RF data is 12 bits only */ + if (BitMask != bRFRegOffsetMask) { + Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + Data = ((Original_Value & (~BitMask)) | (Data << BitShift)); + } + + phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data); +} + +/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */ + +/*----------------------------------------------------------------------------- + * Function: PHY_MACConfig8723A + * + * Overview: Condig MAC by header file or parameter file. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 08/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +s32 PHY_MACConfig8723A(struct rtw_adapter *Adapter) +{ + int rtStatus = _SUCCESS; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + s8 *pszMACRegFile; + s8 sz8723MACRegFile[] = RTL8723_PHY_MACREG; + bool is92C = IS_92C_SERIAL(pHalData->VersionID); + + pszMACRegFile = sz8723MACRegFile; + + /* */ + /* Config MAC */ + /* */ + if (HAL_STATUS_FAILURE == + ODM_ConfigMACWithHeaderFile23a(&pHalData->odmpriv)) + rtStatus = _FAIL; + + /* 2010.07.13 AMPDU aggregation number 9 */ + /* rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); */ + rtw_write8(Adapter, REG_MAX_AGGR_NUM, 0x0A); /* By tynli. 2010.11.18. */ + if (is92C && (BOARD_USB_DONGLE == pHalData->BoardType)) + rtw_write8(Adapter, 0x40, 0x04); + + return rtStatus; +} + +/** +* Function: phy_InitBBRFRegisterDefinition +* +* OverView: Initialize Register definition offset for Radio Path A/B/C/D +* +* Input: +* struct rtw_adapter * Adapter, +* +* Output: None +* Return: None +* Note: +* The initialization value is constant and it should never be changes +*/ +static void +phy_InitBBRFRegisterDefinition(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + /* RF Interface Sowrtware Control */ + /* 16 LSBs if read 32-bit from 0x870 */ + pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; + /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ + pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; + /* 16 LSBs if read 32-bit from 0x874 */ + pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW; + /* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ + pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW; + + /* RF Interface Readback Value */ + /* 16 LSBs if read 32-bit from 0x8E0 */ + pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; + /* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ + pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB; + /* 16 LSBs if read 32-bit from 0x8E4 */ + pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB; + /* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ + pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB; + + /* RF Interface Output (and Enable) */ + /* 16 LSBs if read 32-bit from 0x860 */ + pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; + /* 16 LSBs if read 32-bit from 0x864 */ + pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; + + /* RF Interface (Output and) Enable */ + /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ + pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; + /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ + pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; + + /* Addr of LSSI. Wirte RF register by driver */ + pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; + pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; + + /* RF parameter */ + /* BB Band Select */ + pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; + pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; + pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; + pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; + pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; + pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; + pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; + + /* Tranceiver A~D HSSI Parameter-1 */ + /* wire control parameter1 */ + pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; + /* wire control parameter1 */ + pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; + + /* Tranceiver A~D HSSI Parameter-2 */ + /* wire control parameter2 */ + pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; + /* wire control parameter2 */ + pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; + + /* RF switch Control */ + pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = + rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */ + pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = + rFPGA0_XAB_SwitchControl; + pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = + rFPGA0_XCD_SwitchControl; + pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = + rFPGA0_XCD_SwitchControl; + + /* AGC control 1 */ + pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; + pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; + pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; + pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; + + /* AGC control 2 */ + pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; + pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; + pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; + pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; + + /* RX AFE control 1 */ + pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; + pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; + pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; + pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; + + /* RX AFE control 1 */ + pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE; + pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; + pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; + pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; + + /* Tx AFE control 1 */ + pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; + pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; + pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; + pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; + + /* Tx AFE control 2 */ + pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE; + pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; + pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; + pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; + + /* Tranceiver LSSI Readback SI mode */ + pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; + pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; + pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; + pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; + + /* Tranceiver LSSI Readback PI mode */ + pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = + TransceiverA_HSPI_Readback; + pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = + TransceiverB_HSPI_Readback; + /* pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBackPi = + rFPGA0_XC_LSSIReadBack; */ + /* pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBackPi = + rFPGA0_XD_LSSIReadBack; */ + +} + +/* The following is for High Power PA */ +static void +storePwrIndexDiffRateOffset(struct rtw_adapter *Adapter, u32 RegAddr, + u32 BitMask, u32 Data) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + if (RegAddr == rTxAGC_A_Rate18_06) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][0])); */ + } + if (RegAddr == rTxAGC_A_Rate54_24) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][1] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][1])); */ + } + if (RegAddr == rTxAGC_A_CCK1_Mcs32) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][6] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][6])); */ + } + if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][7] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][7])); */ + } + if (RegAddr == rTxAGC_A_Mcs03_Mcs00) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][2] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][2])); */ + } + if (RegAddr == rTxAGC_A_Mcs07_Mcs04) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][3] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][3])); */ + } + if (RegAddr == rTxAGC_A_Mcs11_Mcs08) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][4] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][4])); */ + } + if (RegAddr == rTxAGC_A_Mcs15_Mcs12) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][5] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][5])); */ + } + if (RegAddr == rTxAGC_B_Rate18_06) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][8] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][8])); */ + } + if (RegAddr == rTxAGC_B_Rate54_24) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][9])); */ + } + if (RegAddr == rTxAGC_B_CCK1_55_Mcs32) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][14])); */ + } + if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][15])); */ + } + if (RegAddr == rTxAGC_B_Mcs03_Mcs00) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][10])); */ + } + if (RegAddr == rTxAGC_B_Mcs07_Mcs04) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][11])); */ + } + if (RegAddr == rTxAGC_B_Mcs11_Mcs08) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][12])); */ + } + if (RegAddr == rTxAGC_B_Mcs15_Mcs12) { + pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data; + /* RT_TRACE(COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%lx\n", + pHalData->pwrGroupCnt, */ + /* pHalData->MCSTxPowerLevelOriginalOffset[ + pHalData->pwrGroupCnt][13])); */ + pHalData->pwrGroupCnt++; + } +} + +/*----------------------------------------------------------------------------- + * Function: phy_ConfigBBWithPgHeaderFile + * + * Overview: Config PHY_REG_PG array + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/06/2008 MHC Add later!!!!!!.. Please modify for new files!!!! + * 11/10/2008 tynli Modify to mew files. + *---------------------------------------------------------------------------*/ +static int +phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter, u8 ConfigType) +{ + int i; + u32 *Rtl819XPHY_REGArray_Table_PG; + u16 PHY_REGArrayPGLen; + + PHY_REGArrayPGLen = Rtl8723_PHY_REG_Array_PGLength; + Rtl819XPHY_REGArray_Table_PG = (u32 *)Rtl8723_PHY_REG_Array_PG; + + if (ConfigType == BaseBand_Config_PHY_REG) { + for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) { + storePwrIndexDiffRateOffset(Adapter, + Rtl819XPHY_REGArray_Table_PG[i], + Rtl819XPHY_REGArray_Table_PG[i+1], + Rtl819XPHY_REGArray_Table_PG[i+2]); + } + } + + return _SUCCESS; +} /* phy_ConfigBBWithPgHeaderFile */ + +static void +phy_BB8192C_Config_1T(struct rtw_adapter *Adapter) +{ + /* for path - B */ + PHY_SetBBReg(Adapter, rFPGA0_TxInfo, 0x3, 0x2); + PHY_SetBBReg(Adapter, rFPGA1_TxInfo, 0x300033, 0x200022); + + /* 20100519 Joseph: Add for 1T2R config. Suggested by Kevin, + Jenyu and Yunan. */ + PHY_SetBBReg(Adapter, rCCK0_AFESetting, bMaskByte3, 0x45); + PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, bMaskByte0, 0x23); + /* B path first AGC */ + PHY_SetBBReg(Adapter, rOFDM0_AGCParameter1, 0x30, 0x1); + + PHY_SetBBReg(Adapter, 0xe74, 0x0c000000, 0x2); + PHY_SetBBReg(Adapter, 0xe78, 0x0c000000, 0x2); + PHY_SetBBReg(Adapter, 0xe7c, 0x0c000000, 0x2); + PHY_SetBBReg(Adapter, 0xe80, 0x0c000000, 0x2); + PHY_SetBBReg(Adapter, 0xe88, 0x0c000000, 0x2); +} + +static int +phy_BB8723a_Config_ParaFile(struct rtw_adapter *Adapter) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + int rtStatus = _SUCCESS; + + u8 sz8723BBRegFile[] = RTL8723_PHY_REG; + u8 sz8723AGCTableFile[] = RTL8723_AGC_TAB; + u8 sz8723BBRegPgFile[] = RTL8723_PHY_REG_PG; + u8 sz8723BBRegMpFile[] = RTL8723_PHY_REG_MP; + + u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL; + u8 *pszBBRegPgFile = NULL, *pszBBRegMpFile = NULL; + + /* RT_TRACE(COMP_INIT, DBG_TRACE, ("==>phy_BB8192S_Config_ParaFile\n")); */ + + pszBBRegFile = sz8723BBRegFile ; + pszAGCTableFile = sz8723AGCTableFile; + pszBBRegPgFile = sz8723BBRegPgFile; + pszBBRegMpFile = sz8723BBRegMpFile; + + /* */ + /* 1. Read PHY_REG.TXT BB INIT!! */ + /* We will seperate as 88C / 92C according to chip version */ + /* */ + if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile23a(&pHalData->odmpriv, + CONFIG_BB_PHY_REG)) + rtStatus = _FAIL; + if (rtStatus != _SUCCESS) + goto phy_BB8190_Config_ParaFile_Fail; + + /* */ + /* 20100318 Joseph: Config 2T2R to 1T2R if necessary. */ + /* */ + if (pHalData->rf_type == RF_1T2R) { + phy_BB8192C_Config_1T(Adapter); + DBG_8723A("phy_BB8723a_Config_ParaFile():Config to 1T!!\n"); + } + + /* */ + /* 2. If EEPROM or EFUSE autoload OK, We must config by + PHY_REG_PG.txt */ + /* */ + if (pEEPROM->bautoload_fail_flag == false) { + pHalData->pwrGroupCnt = 0; + + rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter, + BaseBand_Config_PHY_REG); + } + + if (rtStatus != _SUCCESS) + goto phy_BB8190_Config_ParaFile_Fail; + + /* */ + /* 3. BB AGC table Initialization */ + /* */ + if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile23a(&pHalData->odmpriv, + CONFIG_BB_AGC_TAB)) + rtStatus = _FAIL; + +phy_BB8190_Config_ParaFile_Fail: + + return rtStatus; +} + +int +PHY_BBConfig8723A(struct rtw_adapter *Adapter) +{ + int rtStatus = _SUCCESS; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 TmpU1B = 0; + u8 CrystalCap; + + phy_InitBBRFRegisterDefinition(Adapter); + + /* Suggested by Scott. tynli_test. 2010.12.30. */ + /* 1. 0x28[1] = 1 */ + TmpU1B = rtw_read8(Adapter, REG_AFE_PLL_CTRL); + udelay(2); + rtw_write8(Adapter, REG_AFE_PLL_CTRL, (TmpU1B|BIT1)); + udelay(2); + + /* 2. 0x29[7:0] = 0xFF */ + rtw_write8(Adapter, REG_AFE_PLL_CTRL+1, 0xff); + udelay(2); + + /* 3. 0x02[1:0] = 2b'11 */ + TmpU1B = rtw_read8(Adapter, REG_SYS_FUNC_EN); + rtw_write8(Adapter, REG_SYS_FUNC_EN, + (TmpU1B | FEN_BB_GLB_RSTn | FEN_BBRSTB)); + + /* 4. 0x25[6] = 0 */ + TmpU1B = rtw_read8(Adapter, REG_AFE_XTAL_CTRL + 1); + rtw_write8(Adapter, REG_AFE_XTAL_CTRL+1, (TmpU1B & (~BIT6))); + + /* 5. 0x24[20] = 0 Advised by SD3 Alex Wang. 2011.02.09. */ + TmpU1B = rtw_read8(Adapter, REG_AFE_XTAL_CTRL+2); + rtw_write8(Adapter, REG_AFE_XTAL_CTRL+2, (TmpU1B & (~BIT4))); + + /* 6. 0x1f[7:0] = 0x07 */ + rtw_write8(Adapter, REG_RF_CTRL, 0x07); + + /* */ + /* Config BB and AGC */ + /* */ + rtStatus = phy_BB8723a_Config_ParaFile(Adapter); + +/* only for B-cut */ + if (pHalData->EEPROMVersion >= 0x01) { + CrystalCap = pHalData->CrystalCap & 0x3F; + PHY_SetBBReg(Adapter, REG_MAC_PHY_CTRL, 0xFFF000, + (CrystalCap | (CrystalCap << 6))); + } + + PHY_SetBBReg(Adapter, REG_LDOA15_CTRL, bMaskDWord, 0x01572505); + return rtStatus; +} + +int +PHY_RFConfig8723A(struct rtw_adapter *Adapter) +{ + int rtStatus = _SUCCESS; + + /* */ + /* RF config */ + /* */ + rtStatus = PHY_RF6052_Config8723A(Adapter); + return rtStatus; +} + +static void getTxPowerIndex(struct rtw_adapter *Adapter, + u8 channel, u8 *cckPowerLevel, u8 *ofdmPowerLevel) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 index = (channel - 1); + /* 1. CCK */ + cckPowerLevel[RF_PATH_A] = pHalData->TxPwrLevelCck[RF_PATH_A][index]; + cckPowerLevel[RF_PATH_B] = pHalData->TxPwrLevelCck[RF_PATH_B][index]; + + /* 2. OFDM for 1S or 2S */ + if (GET_RF_TYPE(Adapter) == RF_1T2R || GET_RF_TYPE(Adapter) == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmPowerLevel[RF_PATH_A] = + pHalData->TxPwrLevelHT40_1S[RF_PATH_A][index]; + ofdmPowerLevel[RF_PATH_B] = + pHalData->TxPwrLevelHT40_1S[RF_PATH_B][index]; + } else if (GET_RF_TYPE(Adapter) == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmPowerLevel[RF_PATH_A] = + pHalData->TxPwrLevelHT40_2S[RF_PATH_A][index]; + ofdmPowerLevel[RF_PATH_B] = + pHalData->TxPwrLevelHT40_2S[RF_PATH_B][index]; + } +} + +static void ccxPowerIndexCheck(struct rtw_adapter *Adapter, u8 channel, + u8 *cckPowerLevel, u8 *ofdmPowerLevel) +{ +} + +/*----------------------------------------------------------------------------- + * Function: SetTxPowerLevel8723A() + * + * Overview: This function is export to "HalCommon" moudule + * We must consider RF path later!!!!!!! + * + * Input: struct rtw_adapter * Adapter + * u8 channel + * + * Output: NONE + * + * Return: NONE + * + *---------------------------------------------------------------------------*/ +void PHY_SetTxPowerLevel8723A(struct rtw_adapter *Adapter, u8 channel) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 cckPowerLevel[2], ofdmPowerLevel[2]; /* [0]:RF-A, [1]:RF-B */ + + if (pHalData->bTXPowerDataReadFromEEPORM == false) + return; + + getTxPowerIndex(Adapter, channel, &cckPowerLevel[0], + &ofdmPowerLevel[0]); + + ccxPowerIndexCheck(Adapter, channel, &cckPowerLevel[0], + &ofdmPowerLevel[0]); + + rtl823a_phy_rf6052setccktxpower(Adapter, &cckPowerLevel[0]); + rtl8723a_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], channel); +} + +/*----------------------------------------------------------------------------- + * Function: PHY_SetBWMode23aCallback8192C() + * + * Overview: Timer callback function for SetSetBWMode23a + * + * Input: PRT_TIMER pTimer + * + * Output: NONE + * + * Return: NONE + * + * Note: + * (1) We do not take j mode into consideration now + * (2) Will two workitem of "switch channel" and + * "switch channel bandwidth" run concurrently? + *---------------------------------------------------------------------------*/ +static void +_PHY_SetBWMode23a92C(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 regBwOpMode; + u8 regRRSR_RSC; + + if (pHalData->rf_chip == RF_PSEUDO_11N) + return; + + /* There is no 40MHz mode in RF_8225. */ + if (pHalData->rf_chip == RF_8225) + return; + + if (Adapter->bDriverStopped) + return; + + /* 3 */ + /* 3<1>Set MAC register */ + /* 3 */ + + regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE); + regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2); + + switch (pHalData->CurrentChannelBW) { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); + break; + case HT_CHANNEL_WIDTH_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); + regRRSR_RSC = (regRRSR_RSC & 0x90) | + (pHalData->nCur40MhzPrimeSC << 5); + rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC); + break; + + default: + break; + } + + /* 3 */ + /* 3<2>Set PHY related register */ + /* 3 */ + switch (pHalData->CurrentChannelBW) { + /* 20 MHz channel*/ + case HT_CHANNEL_WIDTH_20: + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0); + PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0); + PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 1); + + break; + + /* 40 MHz channel*/ + case HT_CHANNEL_WIDTH_40: + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1); + PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1); + + /* Set Control channel to upper or lower. These settings + are required only for 40MHz */ + PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, + (pHalData->nCur40MhzPrimeSC >> 1)); + PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, + pHalData->nCur40MhzPrimeSC); + PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 0); + + PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27), + (pHalData->nCur40MhzPrimeSC == + HAL_PRIME_CHNL_OFFSET_LOWER) ? 2:1); + break; + + default: + /*RT_TRACE(COMP_DBG, DBG_LOUD, + ("PHY_SetBWMode23aCallback8192C(): unknown Bandwidth: %#X\n" \ + , pHalData->CurrentChannelBW));*/ + break; + } + /* Skip over setting of J-mode in BB register here. Default value + is "None J mode". Emily 20070315 */ + + /* Added it for 20/40 mhz switch time evaluation by guangan 070531 */ + /* NowL = PlatformEFIORead4Byte(Adapter, TSFR); */ + /* NowH = PlatformEFIORead4Byte(Adapter, TSFR+4); */ + /* EndTime = ((u64)NowH << 32) + NowL; */ + /* RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode23aCallback8190Pci: time + of SetBWMode23a = %I64d us!\n", (EndTime - BeginTime))); */ + + /* 3<3>Set RF related register */ + switch (pHalData->rf_chip) { + case RF_8225: + /* PHY_SetRF8225Bandwidth(Adapter, + pHalData->CurrentChannelBW); */ + break; + + case RF_8256: + /* Please implement this function in Hal8190PciPhy8256.c */ + /* PHY_SetRF8256Bandwidth(Adapter, + pHalData->CurrentChannelBW); */ + break; + + case RF_8258: + /* Please implement this function in Hal8190PciPhy8258.c */ + /* PHY_SetRF8258Bandwidth(); */ + break; + + case RF_PSEUDO_11N: + /* Do Nothing */ + break; + + case RF_6052: + rtl8723a_phy_rf6052set_bw(Adapter, pHalData->CurrentChannelBW); + break; + + default: + /* RT_ASSERT(false, ("Unknown RFChipID: %d\n", + pHalData->RFChipID)); */ + break; + } + + /* pHalData->SetBWMode23aInProgress = false; */ + + /* RT_TRACE(COMP_SCAN, DBG_LOUD, + ("<== PHY_SetBWMode23aCallback8192C() \n")); */ +} + + /*----------------------------------------------------------------------------- + * Function: SetBWMode23a8190Pci() + * + * Overview: This function is export to "HalCommon" moudule + * + * Input: struct rtw_adapter * Adapter + * enum ht_channel_width Bandwidth 20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: We do not take j mode into consideration now + *---------------------------------------------------------------------------*/ +void +PHY_SetBWMode23a8723A(struct rtw_adapter *Adapter, + enum ht_channel_width Bandwidth, unsigned char Offset) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + enum ht_channel_width tmpBW = pHalData->CurrentChannelBW; + + pHalData->CurrentChannelBW = Bandwidth; + + pHalData->nCur40MhzPrimeSC = Offset; + + if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) + _PHY_SetBWMode23a92C(Adapter); + else + pHalData->CurrentChannelBW = tmpBW; +} + +static void _PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel) +{ + u8 eRFPath; + u32 param1, param2; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + if (Adapter->bNotifyChannelChange) + DBG_8723A("[%s] ch = %d\n", __FUNCTION__, channel); + + /* s1. pre common command - CmdID_SetTxPowerLevel */ + PHY_SetTxPowerLevel8723A(Adapter, channel); + + /* s2. RF dependent command - CmdID_RF_WriteReg, + param1 = RF_CHNLBW, param2 = channel */ + param1 = RF_CHNLBW; + param2 = channel; + for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { + pHalData->RfRegChnlVal[eRFPath] = + (pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2; + PHY_SetRFReg(Adapter, (enum RF_RADIO_PATH)eRFPath, param1, + bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]); + } + + /* s3. post common command - CmdID_End, None */ +} + +void PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 tmpchannel = pHalData->CurrentChannel; + bool result = true; + + if (pHalData->rf_chip == RF_PSEUDO_11N) { + /* return immediately if it is peudo-phy */ + return; + } + + if (channel == 0) + channel = 1; + + pHalData->CurrentChannel = channel; + + if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) { + _PHY_SwChnl8723A(Adapter, channel); + + if (!result) + pHalData->CurrentChannel = tmpchannel; + } else { + pHalData->CurrentChannel = tmpchannel; + } +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c b/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c new file mode 100644 index 000000000000..2a7238bacdc8 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c @@ -0,0 +1,515 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/****************************************************************************** + * + * + * Module: rtl8192c_rf6052.c (Source C File) + * + * Note: Provide RF 6052 series relative API. + * + * Function: + * + * Export: + * + * Abbrev: + * + * History: + * Data Who Remark + * + * 09/25/2008 MHC Create initial version. + * 11/05/2008 MHC Add API for tw power setting. + * + * +******************************************************************************/ + +#define _RTL8723A_RF6052_C_ + +#include +#include + +#include + +/*---------------------------Define Local Constant---------------------------*/ +/* Define local structure for debug!!!!! */ +struct rf_shadow_compare_map { + /* Shadow register value */ + u32 Value; + /* Compare or not flag */ + u8 Compare; + /* Record If it had ever modified unpredicted */ + u8 ErrorOrNot; + /* Recorver Flag */ + u8 Recorver; + /* */ + u8 Driver_Write; +}; + +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetBandwidth() + * + * Overview: This function is called by SetBWMode23aCallback8190Pci() only + * + * Input: struct rtw_adapter * Adapter + * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: For RF type 0222D + *---------------------------------------------------------------------------*/ +void rtl8723a_phy_rf6052set_bw( + struct rtw_adapter *Adapter, + enum ht_channel_width Bandwidth) /* 20M or 40M */ +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + switch (Bandwidth) { + case HT_CHANNEL_WIDTH_20: + pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | 0x0400); + PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); + break; + case HT_CHANNEL_WIDTH_40: + pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff)); + PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); + break; + default: + break; + } +} + +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetCckTxPower + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/05/2008 MHC Simulate 8192series.. + * + *---------------------------------------------------------------------------*/ + +void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter, u8 *pPowerlevel) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + u32 TxAGC[2] = {0, 0}, tmpval = 0; + bool TurboScanOff = false; + u8 idx1, idx2; + u8 *ptr; + + /* According to SD3 eechou's suggestion, we need to disable turbo scan for RU. */ + /* Otherwise, external PA will be broken if power index > 0x20. */ + if (pHalData->EEPROMRegulatory != 0 || pHalData->ExternalPA) + TurboScanOff = true; + + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + TxAGC[RF_PATH_A] = 0x3f3f3f3f; + TxAGC[RF_PATH_B] = 0x3f3f3f3f; + + TurboScanOff = true;/* disable turbo scan */ + + if (TurboScanOff) { + for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { + TxAGC[idx1] = + pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | + (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); + /* 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */ + if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA) + TxAGC[idx1] = 0x20; + } + } + } else { +/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ +/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ +/* In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */ + if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { + TxAGC[RF_PATH_A] = 0x10101010; + TxAGC[RF_PATH_B] = 0x10101010; + } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) { + TxAGC[RF_PATH_A] = 0x00000000; + TxAGC[RF_PATH_B] = 0x00000000; + } else { + for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { + TxAGC[idx1] = + pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | + (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); + } + + if (pHalData->EEPROMRegulatory == 0) { + tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) + + (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8); + TxAGC[RF_PATH_A] += tmpval; + + tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) + + (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24); + TxAGC[RF_PATH_B] += tmpval; + } + } + } + + for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { + ptr = (u8 *)(&TxAGC[idx1]); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + + /* rf-A cck tx power */ + tmpval = TxAGC[RF_PATH_A]&0xff; + PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); + tmpval = TxAGC[RF_PATH_A]>>8; + PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + + /* rf-B cck tx power */ + tmpval = TxAGC[RF_PATH_B]>>24; + PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); + tmpval = TxAGC[RF_PATH_B]&0x00ffffff; + PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); +} /* PHY_RF6052SetCckTxPower */ + +/* powerbase0 for OFDM rates */ +/* powerbase1 for HT MCS rates */ +static void getPowerBase( + struct rtw_adapter *Adapter, + u8 *pPowerLevel, + u8 Channel, + u32 *OfdmBase, + u32 *MCSBase + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u32 powerBase0, powerBase1; + u8 Legacy_pwrdiff = 0; + s8 HT20_pwrdiff = 0; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerlevel[i] = pPowerLevel[i]; + Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1]; + powerBase0 = powerlevel[i] + Legacy_pwrdiff; + + powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0; + *(OfdmBase+i) = powerBase0; + } + + for (i = 0; i < 2; i++) { + /* Check HT20 to HT40 diff */ + if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { + HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1]; + powerlevel[i] += HT20_pwrdiff; + } + powerBase1 = powerlevel[i]; + powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1; + *(MCSBase+i) = powerBase1; + } +} + +static void getTxPowerWriteValByRegulatory( + struct rtw_adapter *Adapter, + u8 Channel, + u8 index, + u32 *powerBase0, + u32 *powerBase1, + u32 *pOutWriteVal + ) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + u8 i, chnlGroup = 0, pwr_diff_limit[4]; + u32 writeVal, customer_limit, rf; + + /* Index 0 & 1 = legacy OFDM, 2-5 = HT_MCS rate */ + for (rf = 0; rf < 2; rf++) { + switch (pHalData->EEPROMRegulatory) { + case 0: /* Realtek better performance */ + /* increase power diff defined by Realtek for large power */ + chnlGroup = 0; + writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + break; + case 1: /* Realtek regulatory */ + /* increase power diff defined by Realtek for regulatory */ + if (pHalData->pwrGroupCnt == 1) + chnlGroup = 0; + if (pHalData->pwrGroupCnt >= 3) { + if (Channel <= 3) + chnlGroup = 0; + else if (Channel >= 4 && Channel <= 9) + chnlGroup = 1; + else if (Channel > 9) + chnlGroup = 2; + + if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + chnlGroup++; + else + chnlGroup += 4; + } + writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + break; + case 2: /* Better regulatory */ + /* don't increase any power diff */ + writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + break; + case 3: /* Customer defined power diff. */ + chnlGroup = 0; + + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + + (rf ? 8 : 0)]&(0x7f << (i*8))) >> (i*8)); + if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) { + if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1]) + pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1]; + } else { + if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1]) + pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1]; + } + } + customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | + (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); + writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]); + break; + default: + chnlGroup = 0; + writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + break; + } + +/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ +/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ +/* In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */ + + if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) + writeVal = 0x14141414; + else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) + writeVal = 0x00000000; + + /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */ + /* This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */ + if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) + writeVal = writeVal - 0x06060606; + else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) + writeVal = writeVal; + *(pOutWriteVal+rf) = writeVal; + } +} + +static void writeOFDMPowerReg(struct rtw_adapter *Adapter, u8 index, u32 *pValue) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u16 RegOffset_A[6] = { + rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24, + rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04, + rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 + }; + u16 RegOffset_B[6] = { + rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24, + rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04, + rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 + }; + u8 i, rf, pwr_val[4]; + u32 writeVal; + u16 RegOffset; + + for (rf = 0; rf < 2; rf++) { + writeVal = pValue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8)); + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) | + (pwr_val[1]<<8) | pwr_val[0]; + + if (rf == 0) + RegOffset = RegOffset_A[index]; + else + RegOffset = RegOffset_B[index]; + + PHY_SetBBReg(Adapter, RegOffset, bMaskDWord, writeVal); + + /* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */ + if (((pHalData->rf_type == RF_2T2R) && + (RegOffset == rTxAGC_A_Mcs15_Mcs12 || + RegOffset == rTxAGC_B_Mcs15_Mcs12)) || + ((pHalData->rf_type != RF_2T2R) && + (RegOffset == rTxAGC_A_Mcs07_Mcs04 || + RegOffset == rTxAGC_B_Mcs07_Mcs04))) { + writeVal = pwr_val[3]; + if (RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_A_Mcs07_Mcs04) + RegOffset = 0xc90; + if (RegOffset == rTxAGC_B_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs07_Mcs04) + RegOffset = 0xc98; + for (i = 0; i < 3; i++) { + if (i != 2) + writeVal = (writeVal > 8) ? (writeVal-8) : 0; + else + writeVal = (writeVal > 6) ? (writeVal-6) : 0; + rtw_write8(Adapter, (u32)(RegOffset+i), (u8)writeVal); + } + } + } +} +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetOFDMTxPower + * + * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for + * different channel and read original value in TX power register area from + * 0xe00. We increase offset and original value to be correct tx pwr. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/05/2008 MHC Simulate 8192 series method. + * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to + * A/B pwr difference or legacy/HT pwr diff. + * 2. We concern with path B legacy/HT OFDM difference. + * 01/22/2009 MHC Support new EPRO format from SD3. + * + *---------------------------------------------------------------------------*/ +void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter, u8 *pPowerLevel, u8 Channel) +{ + u32 writeVal[2], powerBase0[2], powerBase1[2]; + u8 index = 0; + + getPowerBase(Adapter, pPowerLevel, Channel, &powerBase0[0], &powerBase1[0]); + + for (index = 0; index < 6; index++) { + getTxPowerWriteValByRegulatory(Adapter, Channel, index, + &powerBase0[0], &powerBase1[0], &writeVal[0]); + + writeOFDMPowerReg(Adapter, index, &writeVal[0]); + } +} + +static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter) +{ + u32 u4RegValue = 0; + u8 eRFPath; + struct bb_reg_define *pPhyReg; + int rtStatus = _SUCCESS; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + static char sz8723RadioAFile[] = RTL8723_PHY_RADIO_A; + static char sz8723RadioBFile[] = RTL8723_PHY_RADIO_B; + char *pszRadioAFile, *pszRadioBFile; + + pszRadioAFile = sz8723RadioAFile; + pszRadioBFile = sz8723RadioBFile; + + /* 3----------------------------------------------------------------- */ + /* 3 <2> Initialize RF */ + /* 3----------------------------------------------------------------- */ + for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { + + pPhyReg = &pHalData->PHYRegDef[eRFPath]; + + /*----Store original RFENV control type----*/ + switch (eRFPath) { + case RF_PATH_A: + case RF_PATH_C: + u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); + break; + case RF_PATH_B: + case RF_PATH_D: + u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); + break; + } + + /*----Set RF_ENV enable----*/ + PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + udelay(1);/* PlatformStallExecution(1); */ + + /*----Set RF_ENV output high----*/ + PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + udelay(1);/* PlatformStallExecution(1); */ + + /* Set bit number of Address and Data for RF register */ + PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */ + udelay(1);/* PlatformStallExecution(1); */ + + PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */ + udelay(1);/* PlatformStallExecution(1); */ + + /*----Initialize RF fom connfiguration file----*/ + switch (eRFPath) { + case RF_PATH_A: + if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile23a(&pHalData->odmpriv, (enum RF_RADIO_PATH)eRFPath, (enum RF_RADIO_PATH)eRFPath)) + rtStatus = _FAIL; + break; + case RF_PATH_B: + if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile23a(&pHalData->odmpriv, (enum RF_RADIO_PATH)eRFPath, (enum RF_RADIO_PATH)eRFPath)) + rtStatus = _FAIL; + break; + case RF_PATH_C: + break; + case RF_PATH_D: + break; + } + + /*----Restore RFENV control type----*/; + switch (eRFPath) { + case RF_PATH_A: + case RF_PATH_C: + PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); + break; + case RF_PATH_B: + case RF_PATH_D: + PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); + break; + } + + if (rtStatus != _SUCCESS) { + /* RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); */ + goto phy_RF6052_Config_ParaFile_Fail; + } + } +phy_RF6052_Config_ParaFile_Fail: + return rtStatus; +} + +int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + int rtStatus = _SUCCESS; + + /* Initialize general global value */ + /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */ + if (pHalData->rf_type == RF_1T1R) + pHalData->NumTotalRFPath = 1; + else + pHalData->NumTotalRFPath = 2; + + /* Config BB and RF */ + rtStatus = phy_RF6052_Config_ParaFile(Adapter); + return rtStatus; +} + +/* End of HalRf6052.c */ diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c b/drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c new file mode 100644 index 000000000000..81b5efe649fa --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8723A_REDESC_C_ + +#include +#include +#include + +static void process_rssi(struct rtw_adapter *padapter, + struct recv_frame *prframe) +{ + struct rx_pkt_attrib *pattrib = &prframe->attrib; + struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data; + + if (signal_stat->update_req) { + signal_stat->total_num = 0; + signal_stat->total_val = 0; + signal_stat->update_req = 0; + } + + signal_stat->total_num++; + signal_stat->total_val += pattrib->phy_info.SignalStrength; + signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; +} + +static void process_link_qual(struct rtw_adapter *padapter, + struct recv_frame *prframe) +{ + struct rx_pkt_attrib *pattrib; + struct signal_stat *signal_stat; + + if (prframe == NULL || padapter == NULL) + return; + + pattrib = &prframe->attrib; + signal_stat = &padapter->recvpriv.signal_qual_data; + + if (signal_stat->update_req) { + signal_stat->total_num = 0; + signal_stat->total_val = 0; + signal_stat->update_req = 0; + } + + signal_stat->total_num++; + signal_stat->total_val += pattrib->phy_info.SignalQuality; + signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; +} + +/* void rtl8723a_process_phy_info(struct rtw_adapter *padapter, union recv_frame *prframe) */ +void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe) +{ + struct recv_frame *precvframe = prframe; + /* Check RSSI */ + process_rssi(padapter, precvframe); + /* Check EVM */ + process_link_qual(padapter, precvframe); +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_sreset.c b/drivers/staging/rtl8723au/hal/rtl8723a_sreset.c new file mode 100644 index 000000000000..c0218e734b9e --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_sreset.c @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8723A_SRESET_C_ + +#include +#include + +void rtl8723a_sreset_xmit_status_check(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + unsigned long current_time; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + unsigned int diff_time; + u32 txdma_status; + + txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS); + if (txdma_status != 0) { + DBG_8723A("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status); + rtw_hal_sreset_reset23a(padapter); + } + + current_time = jiffies; + + if (0 == pxmitpriv->free_xmitbuf_cnt || 0 == pxmitpriv->free_xmit_extbuf_cnt) { + + diff_time = jiffies_to_msecs(jiffies - psrtpriv->last_tx_time); + + if (diff_time > 2000) { + if (psrtpriv->last_tx_complete_time == 0) { + psrtpriv->last_tx_complete_time = current_time; + } else { + diff_time = jiffies_to_msecs(jiffies - psrtpriv->last_tx_complete_time); + if (diff_time > 4000) { + /* padapter->Wifi_Error_Status = WIFI_TX_HANG; */ + DBG_8723A("%s tx hang\n", __func__); + rtw_hal_sreset_reset23a(padapter); + } + } + } + } + + if (psrtpriv->dbg_trigger_point == SRESET_TGP_XMIT_STATUS) { + psrtpriv->dbg_trigger_point = SRESET_TGP_NULL; + rtw_hal_sreset_reset23a(padapter); + return; + } +} + +void rtl8723a_sreset_linked_status_check(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + if (psrtpriv->dbg_trigger_point == SRESET_TGP_LINK_STATUS) { + psrtpriv->dbg_trigger_point = SRESET_TGP_NULL; + rtw_hal_sreset_reset23a(padapter); + return; + } +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723a_xmit.c new file mode 100644 index 000000000000..d7612ccc47e9 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723a_xmit.c @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8723A_XMIT_C_ + +#include +#include +#include + +void dump_txrpt_ccx_8723a(void *buf) +{ + struct txrpt_ccx_8723a *txrpt_ccx = buf; + + DBG_8723A("%s:\n" + "tag1:%u, rsvd:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n" + "mac_id:%u, pkt_drop:%u, pkt_ok:%u, bmc:%u\n" + "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n" + "ccx_qtime:%u\n" + "final_data_rate:0x%02x\n" + "qsel:%u, sw:0x%03x\n" + , __func__ + , txrpt_ccx->tag1, txrpt_ccx->rsvd, txrpt_ccx->int_bt, txrpt_ccx->int_tri, txrpt_ccx->int_ccx + , txrpt_ccx->mac_id, txrpt_ccx->pkt_drop, txrpt_ccx->pkt_ok, txrpt_ccx->bmc + , txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over, txrpt_ccx->retry_over + , txrpt_ccx_qtime_8723a(txrpt_ccx) + , txrpt_ccx->final_data_rate + , txrpt_ccx->qsel, txrpt_ccx_sw_8723a(txrpt_ccx) + ); +} + +void handle_txrpt_ccx_8723a(struct rtw_adapter *adapter, void *buf) +{ + struct txrpt_ccx_8723a *txrpt_ccx = buf; + + if (txrpt_ccx->int_ccx) { + if (txrpt_ccx->pkt_ok) + rtw_ack_tx_done23a(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS); + else + rtw_ack_tx_done23a(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); + } +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_led.c b/drivers/staging/rtl8723au/hal/rtl8723au_led.c new file mode 100644 index 000000000000..4d5c909487f8 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723au_led.c @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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" +#include "rtl8723a_hal.h" +#include "rtl8723a_led.h" + +/* */ +/* LED object. */ +/* */ + +/* */ +/* Prototype of protected function. */ +/* */ + +/* */ +/* LED_819xUsb routines. */ +/* */ + +/* Description: */ +/* Turn on LED according to LedPin specified. */ +void SwLedOn23a(struct rtw_adapter *padapter, struct led_8723a *pLed) +{ + u8 LedCfg = 0; + + if ((padapter->bSurpriseRemoved == true) || (padapter->bDriverStopped == true)) + return; + switch (pLed->LedPin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtw_write8(padapter, REG_LEDCFG0, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */ + break; + case LED_PIN_LED1: + rtw_write8(padapter, REG_LEDCFG1, (LedCfg&0x00)|BIT6); /* SW control led1 on. */ + break; + case LED_PIN_LED2: + LedCfg = rtw_read8(padapter, REG_LEDCFG2); + rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x80)|BIT5); /* SW control led1 on. */ + break; + default: + break; + } + pLed->bLedOn = true; +} + +/* Description: */ +/* Turn off LED according to LedPin specified. */ +void SwLedOff23a(struct rtw_adapter *padapter, struct led_8723a *pLed) +{ + u8 LedCfg = 0; + /* struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); */ + + if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) + goto exit; + + switch (pLed->LedPin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtw_write8(padapter, REG_LEDCFG0, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */ + break; + case LED_PIN_LED1: + rtw_write8(padapter, REG_LEDCFG1, (LedCfg&0x00)|BIT5|BIT6); /* SW control led1 on. */ + break; + case LED_PIN_LED2: + LedCfg = rtw_read8(padapter, REG_LEDCFG2); + rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x80)|BIT3|BIT5); /* SW control led1 on. */ + break; + default: + break; + } +exit: + pLed->bLedOn = false; +} + +/* Interface to manipulate LED objects. */ + +/* Description: */ +/* Initialize all LED_871x objects. */ +void +rtl8723au_InitSwLeds(struct rtw_adapter *padapter) +{ + struct led_priv *pledpriv = &padapter->ledpriv; + + pledpriv->LedControlHandler = LedControl871x23a; + /* 8723as-vau wifi used led2 */ + InitLed871x23a(padapter, &pledpriv->SwLed0, LED_PIN_LED2); + +/* InitLed871x23a(padapter,&pledpriv->SwLed1, LED_PIN_LED2); */ +} + +/* Description: */ +/* DeInitialize all LED_819xUsb objects. */ +void +rtl8723au_DeInitSwLeds(struct rtw_adapter *padapter) +{ + struct led_priv *ledpriv = &padapter->ledpriv; + + DeInitLed871x23a(&ledpriv->SwLed0); +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_recv.c b/drivers/staging/rtl8723au/hal/rtl8723au_recv.c new file mode 100644 index 000000000000..213d1936109d --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723au_recv.c @@ -0,0 +1,247 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8192CU_RECV_C_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void rtl8723au_init_recvbuf(struct rtw_adapter *padapter, + struct recv_buf *precvbuf) +{ +} + +int rtl8723au_init_recv_priv(struct rtw_adapter *padapter) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + int i, size, res = _SUCCESS; + struct recv_buf *precvbuf; + unsigned long tmpaddr; + unsigned long alignment; + struct sk_buff *pskb; + + tasklet_init(&precvpriv->recv_tasklet, + (void(*)(unsigned long))rtl8723au_recv_tasklet, + (unsigned long)padapter); + + precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!precvpriv->int_in_urb) + DBG_8723A("alloc_urb for interrupt in endpoint fail !!!!\n"); + precvpriv->int_in_buf = kzalloc(USB_INTR_CONTENT_LENGTH, GFP_KERNEL); + if (!precvpriv->int_in_buf) + DBG_8723A("alloc_mem for interrupt in endpoint fail !!!!\n"); + + /* init recv_buf */ + _rtw_init_queue23a(&precvpriv->free_recv_buf_queue); + + size = NR_RECVBUFF * sizeof(struct recv_buf); + precvpriv->precv_buf = kzalloc(size, GFP_KERNEL); + if (!precvpriv->precv_buf) { + res = _FAIL; + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("alloc recv_buf fail!\n")); + goto exit; + } + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + for (i = 0; i < NR_RECVBUFF; i++) { + INIT_LIST_HEAD(&precvbuf->list); + + res = rtw_os_recvbuf_resource_alloc23a(padapter, precvbuf); + if (res == _FAIL) + break; + + precvbuf->adapter = padapter; + + precvbuf++; + } + + precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; + + skb_queue_head_init(&precvpriv->rx_skb_queue); + skb_queue_head_init(&precvpriv->free_recv_skb_queue); + + for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { + size = MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ; + pskb = __netdev_alloc_skb(padapter->pnetdev, size, GFP_KERNEL); + + if (pskb) { + pskb->dev = padapter->pnetdev; + + tmpaddr = (unsigned long)pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); + + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + } + + pskb = NULL; + } + +exit: + return res; +} + +void rtl8723au_free_recv_priv(struct rtw_adapter *padapter) +{ + int i; + struct recv_buf *precvbuf; + struct recv_priv *precvpriv = &padapter->recvpriv; + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + for (i = 0; i < NR_RECVBUFF; i++) { + rtw_os_recvbuf_resource_free23a(padapter, precvbuf); + precvbuf++; + } + + kfree(precvpriv->precv_buf); + + usb_free_urb(precvpriv->int_in_urb); + kfree(precvpriv->int_in_buf); + + if (skb_queue_len(&precvpriv->rx_skb_queue)) + DBG_8723A(KERN_WARNING "rx_skb_queue not empty\n"); + + skb_queue_purge(&precvpriv->rx_skb_queue); + + if (skb_queue_len(&precvpriv->free_recv_skb_queue)) { + DBG_8723A(KERN_WARNING "free_recv_skb_queue not empty, %d\n", + skb_queue_len(&precvpriv->free_recv_skb_queue)); + } + + skb_queue_purge(&precvpriv->free_recv_skb_queue); +} + +void update_recvframe_attrib(struct recv_frame *precvframe, + struct recv_stat *prxstat) +{ + struct rx_pkt_attrib *pattrib; + struct recv_stat report; + struct rxreport_8723a *prxreport; + + report.rxdw0 = le32_to_cpu(prxstat->rxdw0); + report.rxdw1 = le32_to_cpu(prxstat->rxdw1); + report.rxdw2 = le32_to_cpu(prxstat->rxdw2); + report.rxdw3 = le32_to_cpu(prxstat->rxdw3); + report.rxdw4 = le32_to_cpu(prxstat->rxdw4); + report.rxdw5 = le32_to_cpu(prxstat->rxdw5); + + prxreport = (struct rxreport_8723a *)&report; + + pattrib = &precvframe->attrib; + memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); + + /* update rx report to recv_frame attribute */ + pattrib->pkt_len = (u16)prxreport->pktlen; + pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3); + pattrib->physt = (u8)prxreport->physt; + + pattrib->crc_err = (u8)prxreport->crc32; + pattrib->icv_err = (u8)prxreport->icverr; + + pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1); + pattrib->encrypt = (u8)prxreport->security; + + pattrib->qos = (u8)prxreport->qos; + pattrib->priority = (u8)prxreport->tid; + + pattrib->amsdu = (u8)prxreport->amsdu; + + pattrib->seq_num = (u16)prxreport->seq; + pattrib->frag_num = (u8)prxreport->frag; + pattrib->mfrag = (u8)prxreport->mf; + pattrib->mdata = (u8)prxreport->md; + + pattrib->mcs_rate = (u8)prxreport->rxmcs; + pattrib->rxht = (u8)prxreport->rxht; +} + +void update_recvframe_phyinfo(struct recv_frame *precvframe, + struct phy_stat *pphy_status) +{ + struct rtw_adapter *padapter = precvframe->adapter; + struct rx_pkt_attrib *pattrib = &precvframe->attrib; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct odm_phy_info *pPHYInfo = (struct odm_phy_info *)(&pattrib->phy_info); + struct odm_packet_info pkt_info; + u8 *sa = NULL, *da; + struct sta_priv *pstapriv; + struct sta_info *psta; + struct sk_buff *skb = precvframe->pkt; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *wlanhdr = skb->data; + + pkt_info.bPacketMatchBSSID = false; + pkt_info.bPacketToSelf = false; + pkt_info.bPacketBeacon = false; + + pkt_info.bPacketMatchBSSID = + (!ieee80211_is_ctl(hdr->frame_control) && + !pattrib->icv_err && + !pattrib->crc_err && + !memcmp(get_hdr_bssid(wlanhdr), + get_bssid(&padapter->mlmepriv), ETH_ALEN)); + + da = ieee80211_get_DA(hdr); + pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && + (!memcmp(da, myid(&padapter->eeprompriv), ETH_ALEN)); + + pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && + ieee80211_is_beacon(hdr->frame_control); + + pkt_info.StationID = 0xFF; + if (pkt_info.bPacketBeacon) { + if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == true) + sa = padapter->mlmepriv.cur_network.network.MacAddress; + /* to do Ad-hoc */ + } else { + sa = ieee80211_get_SA(hdr); + } + + pstapriv = &padapter->stapriv; + psta = rtw_get_stainfo23a(pstapriv, sa); + if (psta) { + pkt_info.StationID = psta->mac_id; + /* printk("%s ==> StationID(%d)\n", __FUNCTION__, pkt_info.StationID); */ + } + pkt_info.Rate = pattrib->mcs_rate; + + ODM_PhyStatusQuery23a(&pHalData->odmpriv, pPHYInfo, + (u8 *)pphy_status, &pkt_info); + precvframe->psta = NULL; + if (pkt_info.bPacketMatchBSSID && + (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) { + if (psta) { + precvframe->psta = psta; + rtl8723a_process_phy_info(padapter, precvframe); + } + } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) { + if (check_fwstate(&padapter->mlmepriv, + WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == + true) { + if (psta) + precvframe->psta = psta; + } + rtl8723a_process_phy_info(padapter, precvframe); + } +} diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c new file mode 100644 index 000000000000..3165ff5dfa73 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c @@ -0,0 +1,548 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RTL8192C_XMIT_C_ +#include +#include +#include +#include +#include +/* include */ +#include + +s32 rtl8723au_init_xmit_priv(struct rtw_adapter *padapter) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + tasklet_init(&pxmitpriv->xmit_tasklet, + (void(*)(unsigned long))rtl8723au_xmit_tasklet, + (unsigned long)padapter); + return _SUCCESS; +} + +void rtl8723au_free_xmit_priv(struct rtw_adapter *padapter) +{ +} + +static void do_queue_select(struct rtw_adapter *padapter, struct pkt_attrib *pattrib) +{ + u8 qsel; + + qsel = pattrib->priority; + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("### do_queue_select priority =%d , qsel = %d\n", + pattrib->priority, qsel)); + + pattrib->qsel = qsel; +} + +static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz) +{ + int blnSetTxDescOffset; + struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); + + if (pdvobj->ishighspeed) { + if (((sz + TXDESC_SIZE) % 512) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } else { + if (((sz + TXDESC_SIZE) % 64) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } + return blnSetTxDescOffset; +} + +static void rtl8192cu_cal_txdesc_chksum(struct tx_desc *ptxdesc) +{ + u16 *usPtr = (u16 *)ptxdesc; + u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ + u32 index; + u16 checksum = 0; + + /* Clear first */ + ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); + + for (index = 0 ; index < count ; index++) + checksum = checksum ^ le16_to_cpu(*(usPtr + index)); + + ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum); +} + +static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) +{ + if ((pattrib->encrypt > 0) && !pattrib->bswenc) { + switch (pattrib->encrypt) { + /* SEC_TYPE */ + case _WEP40_: + case _WEP104_: + ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); + break; + case _TKIP_: + case _TKIP_WTMIC_: + /* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */ + ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); + break; + case _AES_: + ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000); + break; + case _NO_PRIVACY_: + default: + break; + } + } +} + +static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw) +{ + /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */ + + switch (pattrib->vcs_mode) { + case RTS_CTS: + *pdw |= cpu_to_le32(BIT(12)); + break; + case CTS_TO_SELF: + *pdw |= cpu_to_le32(BIT(11)); + break; + case NONE_VCS: + default: + break; + } + + if (pattrib->vcs_mode) { + *pdw |= cpu_to_le32(BIT(13)); + + /* Set RTS BW */ + if (pattrib->ht_en) { + *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0; + + if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + *pdw |= cpu_to_le32((0x01<<28)&0x30000000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + *pdw |= cpu_to_le32((0x02<<28)&0x30000000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + *pdw |= 0; + else + *pdw |= cpu_to_le32((0x03<<28)&0x30000000); + } + } +} + +static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw) +{ + if (pattrib->ht_en) { + *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0; + + if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + *pdw |= cpu_to_le32((0x01<<20)&0x003f0000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + *pdw |= cpu_to_le32((0x02<<20)&0x003f0000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + *pdw |= 0; + else + *pdw |= cpu_to_le32((0x03<<20)&0x003f0000); + } +} + +static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt) +{ + int pull = 0; + uint qsel; + struct rtw_adapter *padapter = pxmitframe->padapter; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct tx_desc *ptxdesc = (struct tx_desc *)pmem; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + int bmcst = is_multicast_ether_addr(pattrib->ra); + + if ((!bagg_pkt) && (urb_zero_packet_chk(padapter, sz) == 0)) { + ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ); + pull = 1; + pxmitframe->pkt_offset--; + } + + memset(ptxdesc, 0, sizeof(struct tx_desc)); + + if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); + + qsel = (uint)(pattrib->qsel & 0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); + + ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); + + fill_txdesc_sectype(pattrib, ptxdesc); + + if (pattrib->ampdu_en) + ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */ + else + ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ + + /* offset 8 */ + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 , offset 20 */ + if (pattrib->qos_en) + ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */ + + if ((pattrib->ether_type != 0x888e) && + (pattrib->ether_type != 0x0806) && + (pattrib->dhcp_pkt != 1)) { + /* Non EAP & ARP & DHCP type data packet */ + + fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); + fill_txdesc_phy(pattrib, &ptxdesc->txdw4); + + ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */ + ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* */ + + /* use REG_INIDATA_RATE_SEL value */ + ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]); + } else { + /* EAP data packet and ARP packet. */ + /* Use the 1M data rate to send the EAP/ARP packet. */ + /* This will maybe make the handshake smooth. */ + + ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ + + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) + ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */ + + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } + } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); + + qsel = (uint)(pattrib->qsel&0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel<txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); + + /* offset 8 */ + /* CCX-TXRPT ack for xmit mgmt frames. */ + if (pxmitframe->ack_report) + ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + /* offset 20 */ + ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */ + ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */ + + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) { + DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); + } else { + DBG_8723A("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); + + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */ + + ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */ + + /* offset 8 */ + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + /* offset 20 */ + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } + + /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ + /* mgnt frame should be controled by Hw because Fw will also send null data */ + /* which we cannot control when Fw LPS enable. */ + /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ + /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ + /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ + if (!pattrib->qos_en) { + /* Hw set sequence number */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); + /* set bit3 to 1. */ + ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); + } + + /* offset 0 */ + ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); + ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(BIT(24)); + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("offset0-txdesc = 0x%x\n", ptxdesc->txdw0)); + + /* offset 4 */ + /* pkt_offset, unit:8 bytes padding */ + if (pxmitframe->pkt_offset > 0) + ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); + + rtl8192cu_cal_txdesc_chksum(ptxdesc); + return pull; +} + +static s32 rtw_dump_xframe(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + s32 ret = _SUCCESS; + s32 inner_ret = _SUCCESS; + int t, sz, w_sz, pull = 0; + u8 *mem_addr; + u32 ff_hwaddr; + struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if ((pxmitframe->frame_tag == DATA_FRAMETAG) && + (pxmitframe->attrib.ether_type != 0x0806) && + (pxmitframe->attrib.ether_type != 0x888e) && + (pxmitframe->attrib.dhcp_pkt != 1)) + rtw_issue_addbareq_cmd23a(padapter, pxmitframe); + + mem_addr = pxmitframe->buf_addr; + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n")); + + for (t = 0; t < pattrib->nr_frags; t++) { + if (inner_ret != _SUCCESS && ret == _SUCCESS) + ret = _FAIL; + + if (t != (pattrib->nr_frags - 1)) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + ("pattrib->nr_frags =%d\n", pattrib->nr_frags)); + + sz = pxmitpriv->frag_len; + sz = sz - 4 - pattrib->icv_len; + } else { + /* no frag */ + sz = pattrib->last_txcmdsz; + } + + pull = update_txdesc(pxmitframe, mem_addr, sz, false); + + if (pull) { + mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */ + + pxmitframe->buf_addr = mem_addr; + + w_sz = sz + TXDESC_SIZE; + } else { + w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; + } + + ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe); + inner_ret = rtw_write_port(padapter, ff_hwaddr, w_sz, pxmitbuf); + rtw_count_tx_stats23a(padapter, pxmitframe, sz); + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + ("rtw_write_port, w_sz =%d\n", w_sz)); + + mem_addr += w_sz; + + mem_addr = (u8 *)RND4(((unsigned long)(mem_addr))); + } + + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + if (ret != _SUCCESS) + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); + + return ret; +} + +s32 rtl8723au_xmitframe_complete(struct rtw_adapter *padapter, + struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + struct hw_xmit *phwxmits; + struct xmit_frame *pxmitframe; + int hwentry; + int res = _SUCCESS, xcnt = 0; + + phwxmits = pxmitpriv->hwxmits; + hwentry = pxmitpriv->hwxmit_entry; + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete()\n")); + + if (pxmitbuf == NULL) { + pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); + if (!pxmitbuf) + return false; + } + pxmitframe = rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry); + + if (pxmitframe) { + pxmitframe->pxmitbuf = pxmitbuf; + + pxmitframe->buf_addr = pxmitbuf->pbuf; + + pxmitbuf->priv_data = pxmitframe; + + if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { + if (pxmitframe->attrib.priority <= 15)/* TID0~15 */ + res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); + + rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */ + } + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete(): rtw_dump_xframe\n")); + + if (res == _SUCCESS) { + rtw_dump_xframe(padapter, pxmitframe); + } else { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + } + xcnt++; + } else { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + return false; + } + return true; +} + +static s32 xmitframe_direct(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + s32 res = _SUCCESS; + + res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); + if (res == _SUCCESS) + rtw_dump_xframe(padapter, pxmitframe); + return res; +} + +/* + * Return + * true dump packet directly + * false enqueue packet + */ +static s32 pre_xmitframe(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + s32 res; + struct xmit_buf *pxmitbuf = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + do_queue_select(padapter, pattrib); + spin_lock_bh(&pxmitpriv->lock); + +#ifdef CONFIG_8723AU_AP_MODE + if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + spin_unlock_bh(&pxmitpriv->lock); + + if (pattrib->psta) + psta = pattrib->psta; + else + psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); + + if (psta) { + if (psta->sleepq_len > (NR_XMITFRAME>>3)) + wakeup_sta_to_xmit23a(padapter, psta); + } + + return false; + } +#endif + + if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0) + goto enqueue; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) + goto enqueue; + + pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); + if (pxmitbuf == NULL) + goto enqueue; + + spin_unlock_bh(&pxmitpriv->lock); + + pxmitframe->pxmitbuf = pxmitbuf; + pxmitframe->buf_addr = pxmitbuf->pbuf; + pxmitbuf->priv_data = pxmitframe; + + if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + } + return true; + +enqueue: + res = rtw_xmitframe_enqueue23a(padapter, pxmitframe); + spin_unlock_bh(&pxmitpriv->lock); + + if (res != _SUCCESS) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, + ("pre_xmitframe: enqueue xmitframe fail\n")); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + /* Trick, make the statistics correct */ + pxmitpriv->tx_pkts--; + pxmitpriv->tx_drop++; + return true; + } + return false; +} + +s32 rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe) +{ + return rtw_dump_xframe(padapter, pmgntframe); +} + +/* + * Return + * true dump packet directly ok + * false temporary can't transmit packets to hardware + */ +s32 rtl8723au_hal_xmit(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe) +{ + return pre_xmitframe(padapter, pxmitframe); +} + +s32 rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + s32 err; + + err = rtw_xmitframe_enqueue23a(padapter, pxmitframe); + if (err != _SUCCESS) { + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + /* Trick, make the statistics correct */ + pxmitpriv->tx_pkts--; + pxmitpriv->tx_drop++; + } else { + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); + } + return err; +} diff --git a/drivers/staging/rtl8723au/hal/usb_halinit.c b/drivers/staging/rtl8723au/hal/usb_halinit.c new file mode 100644 index 000000000000..e206829d50fa --- /dev/null +++ b/drivers/staging/rtl8723au/hal/usb_halinit.c @@ -0,0 +1,1834 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _HCI_HAL_INIT_C_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +static void +_ConfigChipOutEP(struct rtw_adapter *pAdapter, u8 NumOutPipe) +{ + u8 value8; + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + + pHalData->OutEpQueueSel = 0; + pHalData->OutEpNumber = 0; + + /* Normal and High queue */ + value8 = rtw_read8(pAdapter, (REG_NORMAL_SIE_EP + 1)); + + if (value8 & USB_NORMAL_SIE_EP_MASK) { + pHalData->OutEpQueueSel |= TX_SELE_HQ; + pHalData->OutEpNumber++; + } + + if ((value8 >> USB_NORMAL_SIE_EP_SHIFT) & USB_NORMAL_SIE_EP_MASK) { + pHalData->OutEpQueueSel |= TX_SELE_NQ; + pHalData->OutEpNumber++; + } + + /* Low queue */ + value8 = rtw_read8(pAdapter, (REG_NORMAL_SIE_EP + 2)); + if (value8 & USB_NORMAL_SIE_EP_MASK) { + pHalData->OutEpQueueSel |= TX_SELE_LQ; + pHalData->OutEpNumber++; + } + + /* TODO: Error recovery for this case */ + /* RT_ASSERT((NumOutPipe == pHalData->OutEpNumber), + ("Out EP number isn't match! %d(Descriptor) != %d (SIE reg)\n", + (u32)NumOutPipe, (u32)pHalData->OutEpNumber)); */ +} + +static bool rtl8723au_set_queue_pipe_mapping(struct rtw_adapter *pAdapter, + u8 NumInPipe, u8 NumOutPipe) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + bool result = false; + + _ConfigChipOutEP(pAdapter, NumOutPipe); + + /* Normal chip with one IN and one OUT doesn't have interrupt IN EP. */ + if (pHalData->OutEpNumber == 1) { + if (NumInPipe != 1) + return result; + } + + result = Hal_MappingOutPipe23a(pAdapter, NumOutPipe); + + return result; +} + +static void rtl8723au_interface_configure(struct rtw_adapter *padapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + + if (pdvobjpriv->ishighspeed == true) { + /* 512 bytes */ + pHalData->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE; + } else { + /* 64 bytes */ + pHalData->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE; + } + + pHalData->interfaceIndex = pdvobjpriv->InterfaceNumber; + + rtl8723au_set_queue_pipe_mapping(padapter, + pdvobjpriv->RtNumInPipes, + pdvobjpriv->RtNumOutPipes); +} + +static u8 _InitPowerOn(struct rtw_adapter *padapter) +{ + u8 status = _SUCCESS; + u16 value16 = 0; + u8 value8 = 0; + + /* RSV_CTRL 0x1C[7:0] = 0x00 + unlock ISO/CLK/Power control register */ + rtw_write8(padapter, REG_RSV_CTRL, 0x0); + + /* HW Power on sequence */ + if (!HalPwrSeqCmdParsing23a(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_USB_MSK, rtl8723AU_card_enable_flow)) + return _FAIL; + + /* 0x04[19] = 1, suggest by Jackie 2011.05.09, reset 8051 */ + value8 = rtw_read8(padapter, REG_APS_FSMCO+2); + rtw_write8(padapter, REG_APS_FSMCO + 2, (value8 | BIT3)); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ + /* Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. + Added by tynli. 2011.08.31. */ + value16 = rtw_read16(padapter, REG_CR); + value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN | + PROTOCOL_EN | SCHEDULE_EN | MACTXEN | MACRXEN | + ENSEC | CALTMR_EN); + rtw_write16(padapter, REG_CR, value16); + + /* for Efuse PG, suggest by Jackie 2011.11.23 */ + PHY_SetBBReg(padapter, REG_EFUSE_CTRL, BIT28|BIT29|BIT30, 0x06); + + return status; +} + +/* Shall USB interface init this? */ +static void _InitInterrupt(struct rtw_adapter *Adapter) +{ + u32 value32; + + /* HISR - turn all on */ + value32 = 0xFFFFFFFF; + rtw_write32(Adapter, REG_HISR, value32); + + /* HIMR - turn all on */ + rtw_write32(Adapter, REG_HIMR, value32); +} + +static void _InitQueueReservedPage(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct registry_priv *pregistrypriv = &Adapter->registrypriv; + u32 numHQ = 0; + u32 numLQ = 0; + u32 numNQ = 0; + u32 numPubQ; + u32 value32; + u8 value8; + bool bWiFiConfig = pregistrypriv->wifi_spec; + /* u32 txQPageNum, txQPageUnit, txQRemainPage; */ + + { /* for WMM */ + /* RT_ASSERT((outEPNum>= 2), ("for WMM , number of out-ep " + "must more than or equal to 2!\n")); */ + + numPubQ = bWiFiConfig ? + WMM_NORMAL_PAGE_NUM_PUBQ : NORMAL_PAGE_NUM_PUBQ; + + if (pHalData->OutEpQueueSel & TX_SELE_HQ) { + numHQ = bWiFiConfig ? + WMM_NORMAL_PAGE_NUM_HPQ : NORMAL_PAGE_NUM_HPQ; + } + + if (pHalData->OutEpQueueSel & TX_SELE_LQ) { + numLQ = bWiFiConfig ? + WMM_NORMAL_PAGE_NUM_LPQ : NORMAL_PAGE_NUM_LPQ; + } + /* NOTE: This step shall be proceed before + writting REG_RQPN. */ + if (pHalData->OutEpQueueSel & TX_SELE_NQ) { + numNQ = bWiFiConfig ? + WMM_NORMAL_PAGE_NUM_NPQ : NORMAL_PAGE_NUM_NPQ; + } + value8 = (u8)_NPQ(numNQ); + rtw_write8(Adapter, REG_RQPN_NPQ, value8); + } + + /* TX DMA */ + value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; + rtw_write32(Adapter, REG_RQPN, value32); +} + +static void _InitTxBufferBoundary(struct rtw_adapter *Adapter) +{ + struct registry_priv *pregistrypriv = &Adapter->registrypriv; + + u8 txpktbuf_bndy; + + if (!pregistrypriv->wifi_spec) + txpktbuf_bndy = TX_PAGE_BOUNDARY; + else /* for WMM */ + txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY; + + rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); + rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy); + rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy); +} + +static void _InitPageBoundary(struct rtw_adapter *Adapter) +{ + /* RX Page Boundary */ + /* srand(static_cast(time(NULL))); */ + u16 rxff_bndy = 0x27FF;/* rand() % 1) ? 0x27FF : 0x23FF; */ + + rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); + + /* TODO: ?? shall we set tx boundary? */ +} + +static void +_InitNormalChipRegPriority(struct rtw_adapter *Adapter, u16 beQ, u16 bkQ, + u16 viQ, u16 voQ, u16 mgtQ, u16 hiQ) +{ + u16 value16 = rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7; + + value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | + _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | + _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ); + + rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); +} + +static void _InitNormalChipOneOutEpPriority(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u16 value = 0; + + switch (pHalData->OutEpQueueSel) { + case TX_SELE_HQ: + value = QUEUE_HIGH; + break; + case TX_SELE_LQ: + value = QUEUE_LOW; + break; + case TX_SELE_NQ: + value = QUEUE_NORMAL; + break; + default: + /* RT_ASSERT(false, ("Shall not reach here!\n")); */ + break; + } + + _InitNormalChipRegPriority(Adapter, value, value, value, + value, value, value); +} + +static void _InitNormalChipTwoOutEpPriority(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct registry_priv *pregistrypriv = &Adapter->registrypriv; + u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; + u16 valueHi = 0; + u16 valueLow = 0; + + switch (pHalData->OutEpQueueSel) { + case (TX_SELE_HQ | TX_SELE_LQ): + valueHi = QUEUE_HIGH; + valueLow = QUEUE_LOW; + break; + case (TX_SELE_NQ | TX_SELE_LQ): + valueHi = QUEUE_NORMAL; + valueLow = QUEUE_LOW; + break; + case (TX_SELE_HQ | TX_SELE_NQ): + valueHi = QUEUE_HIGH; + valueLow = QUEUE_NORMAL; + break; + default: + /* RT_ASSERT(false, ("Shall not reach here!\n")); */ + break; + } + + if (!pregistrypriv->wifi_spec) { + beQ = valueLow; + bkQ = valueLow; + viQ = valueHi; + voQ = valueHi; + mgtQ = valueHi; + hiQ = valueHi; + } else {/* for WMM , CONFIG_OUT_EP_WIFI_MODE */ + beQ = valueLow; + bkQ = valueHi; + viQ = valueHi; + voQ = valueLow; + mgtQ = valueHi; + hiQ = valueHi; + } + + _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); +} + +static void _InitNormalChipThreeOutEpPriority(struct rtw_adapter *Adapter) +{ + struct registry_priv *pregistrypriv = &Adapter->registrypriv; + u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; + + if (!pregistrypriv->wifi_spec) {/* typical setting */ + beQ = QUEUE_LOW; + bkQ = QUEUE_LOW; + viQ = QUEUE_NORMAL; + voQ = QUEUE_HIGH; + mgtQ = QUEUE_HIGH; + hiQ = QUEUE_HIGH; + } else {/* for WMM */ + beQ = QUEUE_LOW; + bkQ = QUEUE_NORMAL; + viQ = QUEUE_NORMAL; + voQ = QUEUE_HIGH; + mgtQ = QUEUE_HIGH; + hiQ = QUEUE_HIGH; + } + _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); +} + +static void _InitNormalChipQueuePriority(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + switch (pHalData->OutEpNumber) { + case 1: + _InitNormalChipOneOutEpPriority(Adapter); + break; + case 2: + _InitNormalChipTwoOutEpPriority(Adapter); + break; + case 3: + _InitNormalChipThreeOutEpPriority(Adapter); + break; + default: + /* RT_ASSERT(false, ("Shall not reach here!\n")); */ + break; + } +} + +static void _InitQueuePriority(struct rtw_adapter *Adapter) +{ + _InitNormalChipQueuePriority(Adapter); +} + +static void _InitNetworkType(struct rtw_adapter *Adapter) +{ + u32 value32; + + value32 = rtw_read32(Adapter, REG_CR); + + /* TODO: use the other function to set network type */ + value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); + rtw_write32(Adapter, REG_CR, value32); +} + +static void _InitTransferPageSize(struct rtw_adapter *Adapter) +{ + /* Tx page size is always 128. */ + + u8 value8; + value8 = _PSRX(PBP_128) | _PSTX(PBP_128); + rtw_write8(Adapter, REG_PBP, value8); +} + +static void _InitDriverInfoSize(struct rtw_adapter *Adapter, u8 drvInfoSize) +{ + rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize); +} + +static void _InitWMACSetting(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + /* don't turn on AAP, it will allow all packets to driver */ + pHalData->ReceiveConfig = RCR_APM | RCR_AM | RCR_AB | RCR_CBSSID_DATA | + RCR_CBSSID_BCN | RCR_APP_ICV | RCR_AMF | + RCR_HTC_LOC_CTRL | RCR_APP_MIC | + RCR_APP_PHYSTS; + + /* some REG_RCR will be modified later by + phy_ConfigMACWithHeaderFile() */ + rtw_write32(Adapter, REG_RCR, pHalData->ReceiveConfig); + + /* Accept all multicast address */ + rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF); + rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF); + + /* Accept all data frames */ + /* value16 = 0xFFFF; */ + /* rtw_write16(Adapter, REG_RXFLTMAP2, value16); */ + + /* 2010.09.08 hpfan */ + /* Since ADF is removed from RCR, ps-poll will not be indicate + to driver, */ + /* RxFilterMap should mask ps-poll to gurantee AP mode can + rx ps-poll. */ + /* value16 = 0x400; */ + /* rtw_write16(Adapter, REG_RXFLTMAP1, value16); */ + + /* Accept all management frames */ + /* value16 = 0xFFFF; */ + /* rtw_write16(Adapter, REG_RXFLTMAP0, value16); */ + + /* enable RX_SHIFT bits */ + /* rtw_write8(Adapter, REG_TRXDMA_CTRL, rtw_read8(Adapter, + REG_TRXDMA_CTRL)|BIT(1)); */ +} + +static void _InitAdaptiveCtrl(struct rtw_adapter *Adapter) +{ + u16 value16; + u32 value32; + + /* Response Rate Set */ + value32 = rtw_read32(Adapter, REG_RRSR); + value32 &= ~RATE_BITMAP_ALL; + value32 |= RATE_RRSR_CCK_ONLY_1M; + rtw_write32(Adapter, REG_RRSR, value32); + + /* CF-END Threshold */ + /* m_spIoBase->rtw_write8(REG_CFEND_TH, 0x1); */ + + /* SIFS (used in NAV) */ + value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); + rtw_write16(Adapter, REG_SPEC_SIFS, value16); + + /* Retry Limit */ + value16 = _LRL(0x30) | _SRL(0x30); + rtw_write16(Adapter, REG_RL, value16); +} + +static void _InitRateFallback(struct rtw_adapter *Adapter) +{ + /* Set Data Auto Rate Fallback Retry Count register. */ + rtw_write32(Adapter, REG_DARFRC, 0x00000000); + rtw_write32(Adapter, REG_DARFRC+4, 0x10080404); + rtw_write32(Adapter, REG_RARFRC, 0x04030201); + rtw_write32(Adapter, REG_RARFRC+4, 0x08070605); +} + +static void _InitEDCA(struct rtw_adapter *Adapter) +{ + /* Set Spec SIFS (used in NAV) */ + rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a); + rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a); + + /* Set SIFS for CCK */ + rtw_write16(Adapter, REG_SIFS_CTX, 0x100a); + + /* Set SIFS for OFDM */ + rtw_write16(Adapter, REG_SIFS_TRX, 0x100a); + + /* TXOP */ + rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B); + rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F); + rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324); + rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226); +} + +static void _InitHWLed(struct rtw_adapter *Adapter) +{ + struct led_priv *pledpriv = &Adapter->ledpriv; + + if (pledpriv->LedStrategy != HW_LED) + return; + +/* HW led control */ +/* to do .... */ +/* must consider cases of antenna diversity/ commbo card/solo card/mini card */ +} + +static void _InitRDGSetting(struct rtw_adapter *Adapter) +{ + rtw_write8(Adapter, REG_RD_CTRL, 0xFF); + rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200); + rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05); +} + +static void _InitRetryFunction(struct rtw_adapter *Adapter) +{ + u8 value8; + + value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL); + value8 |= EN_AMPDU_RTY_NEW; + rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8); + + /* Set ACK timeout */ + rtw_write8(Adapter, REG_ACKTO, 0x40); +} + +/*----------------------------------------------------------------------------- + * Function: usb_AggSettingTxUpdate() + * + * Overview: Seperate TX/RX parameters update independent for TP + * detection and dynamic TX/RX aggreagtion parameters update. + * + * Input: struct rtw_adapter * + * + * Output/Return: NONE + * + * Revised History: + * When Who Remark + * 12/10/2010 MHC Seperate to smaller function. + * + *---------------------------------------------------------------------------*/ +static void usb_AggSettingTxUpdate(struct rtw_adapter *Adapter) +{ +} /* usb_AggSettingTxUpdate */ + +/*----------------------------------------------------------------------------- + * Function: usb_AggSettingRxUpdate() + * + * Overview: Seperate TX/RX parameters update independent for TP + * detection and dynamic TX/RX aggreagtion parameters update. + * + * Input: struct rtw_adapter * + * + * Output/Return: NONE + * + * Revised History: + * When Who Remark + * 12/10/2010 MHC Seperate to smaller function. + * + *---------------------------------------------------------------------------*/ +static void usb_AggSettingRxUpdate(struct rtw_adapter *Adapter) +{ +} /* usb_AggSettingRxUpdate */ + +static void InitUsbAggregationSetting(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + /* Tx aggregation setting */ + usb_AggSettingTxUpdate(Adapter); + + /* Rx aggregation setting */ + usb_AggSettingRxUpdate(Adapter); + + /* 201/12/10 MH Add for USB agg mode dynamic switch. */ + pHalData->UsbRxHighSpeedMode = false; +} + +static void _InitOperationMode(struct rtw_adapter *Adapter) +{ +} + +static void _InitRFType(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + bool is92CU = IS_92C_SERIAL(pHalData->VersionID); + + pHalData->rf_chip = RF_6052; + + if (is92CU == false) { + pHalData->rf_type = RF_1T1R; + DBG_8723A("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n"); + return; + } + + /* TODO: Consider that EEPROM set 92CU to 1T1R later. */ + /* Force to overwrite setting according to chip version. Ignore + EEPROM setting. */ + /* pHalData->RF_Type = is92CU ? RF_2T2R : RF_1T1R; */ + MSG_8723A("Set RF Chip ID to RF_6052 and RF type to %d.\n", + pHalData->rf_type); +} + +/* Set CCK and OFDM Block "ON" */ +static void _BBTurnOnBlock(struct rtw_adapter *Adapter) +{ + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1); + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1); +} + +#define MgntActSet_RF_State(...) +static void _RfPowerSave(struct rtw_adapter *padapter) +{ +} + +enum { + Antenna_Lfet = 1, + Antenna_Right = 2, +}; + +enum rt_rf_power_state RfOnOffDetect23a(struct rtw_adapter *pAdapter) +{ + /* struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); */ + u8 val8; + enum rt_rf_power_state rfpowerstate = rf_off; + + if (pAdapter->pwrctrlpriv.bHWPowerdown) { + val8 = rtw_read8(pAdapter, REG_HSISR); + DBG_8723A("pwrdown, 0x5c(BIT7) =%02x\n", val8); + rfpowerstate = (val8 & BIT7) ? rf_off : rf_on; + } else { /* rf on/off */ + rtw_write8(pAdapter, REG_MAC_PINMUX_CFG, + rtw_read8(pAdapter, REG_MAC_PINMUX_CFG) & ~BIT3); + val8 = rtw_read8(pAdapter, REG_GPIO_IO_SEL); + DBG_8723A("GPIO_IN =%02x\n", val8); + rfpowerstate = (val8 & BIT3) ? rf_on : rf_off; + } + return rfpowerstate; +} /* HalDetectPwrDownMode */ + +void _ps_open_RF23a(struct rtw_adapter *padapter); + +static u32 rtl8723au_hal_init(struct rtw_adapter *Adapter) +{ + u8 val8 = 0; + u32 boundary, status = _SUCCESS; + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; + struct registry_priv *pregistrypriv = &Adapter->registrypriv; + u32 NavUpper = WiFiNavUpperUs; + + unsigned long init_start_time = jiffies; + +#define HAL_INIT_PROFILE_TAG(stage) do {} while (0) + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN); + if (Adapter->pwrctrlpriv.bkeepfwalive) { + _ps_open_RF23a(Adapter); + + if (pHalData->bIQKInitialized) { + rtl8723a_phy_iq_calibrate(Adapter, true); + } else { + rtl8723a_phy_iq_calibrate(Adapter, false); + pHalData->bIQKInitialized = true; + } + rtl8723a_odm_check_tx_power_tracking(Adapter); + rtl8723a_phy_lc_calibrate(Adapter); + + goto exit; + } + + /* Check if MAC has already power on. by tynli. 2011.05.27. */ + val8 = rtw_read8(Adapter, REG_CR); + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("%s: REG_CR 0x100 = 0x%02x\n", __func__, val8)); + /* Fix 92DU-VC S3 hang with the reason is that secondary mac is not + initialized. */ + /* 0x100 value of first mac is 0xEA while 0x100 value of secondary + is 0x00 */ + if (val8 == 0xEA) { + pHalData->bMACFuncEnable = false; + } else { + pHalData->bMACFuncEnable = true; + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("%s: MAC has already power on\n", __func__)); + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON); + status = _InitPowerOn(Adapter); + if (status == _FAIL) { + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, + ("Failed to init power on!\n")); + goto exit; + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT); + if (!pregistrypriv->wifi_spec) { + boundary = TX_PAGE_BOUNDARY; + } else { + /* for WMM */ + boundary = WMM_NORMAL_TX_PAGE_BOUNDARY; + } + + if (!pHalData->bMACFuncEnable) { + status = InitLLTTable23a(Adapter, boundary); + if (status == _FAIL) { + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, + ("Failed to init LLT table\n")); + goto exit; + } + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01); + if (pHalData->bRDGEnable) + _InitRDGSetting(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW); + status = rtl8723a_FirmwareDownload(Adapter); + if (status != _SUCCESS) { + Adapter->bFWReady = false; + pHalData->fw_ractrl = false; + DBG_8723A("fw download fail!\n"); + goto exit; + } else { + Adapter->bFWReady = true; + pHalData->fw_ractrl = true; + DBG_8723A("fw download ok!\n"); + } + + rtl8723a_InitializeFirmwareVars(Adapter); + + if (pwrctrlpriv->reg_rfoff == true) { + pwrctrlpriv->rf_pwrstate = rf_off; + } + + /* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */ + /* HW GPIO pin. Before PHY_RFConfig8192C. */ + /* HalDetectPwrDownMode(Adapter); */ + /* 2010/08/26 MH If Efuse does not support sective suspend then disable the function. */ + /* HalDetectSelectiveSuspendMode(Adapter); */ + + /* Set RF type for BB/RF configuration */ + _InitRFType(Adapter);/* _ReadRFType() */ + + /* Save target channel */ + /* Current Channel will be updated again later. */ + pHalData->CurrentChannel = 6;/* default set to 6 */ + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC); + status = PHY_MACConfig8723A(Adapter); + if (status == _FAIL) { + DBG_8723A("PHY_MACConfig8723A fault !!\n"); + goto exit; + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB); + /* */ + /* d. Initialize BB related configurations. */ + /* */ + status = PHY_BBConfig8723A(Adapter); + if (status == _FAIL) { + DBG_8723A("PHY_BBConfig8723A fault !!\n"); + goto exit; + } + + /* Add for tx power by rate fine tune. We need to call the function after BB config. */ + /* Because the tx power by rate table is inited in BB config. */ + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF); + status = PHY_RFConfig8723A(Adapter); + if (status == _FAIL) { + DBG_8723A("PHY_RFConfig8723A fault !!\n"); + goto exit; + } + + /* reducing 80M spur */ + PHY_SetBBReg(Adapter, RF_T_METER, bMaskDWord, 0x0381808d); + PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83); + PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff82); + PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83); + + /* RFSW Control */ + PHY_SetBBReg(Adapter, rFPGA0_TxInfo, bMaskDWord, 0x00000003); /* 0x804[14]= 0 */ + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFInterfaceSW, bMaskDWord, 0x07000760); /* 0x870[6:5]= b'11 */ + PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, 0x66F60210); /* 0x860[6:5]= b'00 */ + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("%s: 0x870 = value 0x%x\n", __func__, PHY_QueryBBReg(Adapter, 0x870, bMaskDWord))); + + /* */ + /* Joseph Note: Keep RfRegChnlVal for later use. */ + /* */ + pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)0, RF_CHNLBW, bRFRegOffsetMask); + pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)1, RF_CHNLBW, bRFRegOffsetMask); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02); + if (!pHalData->bMACFuncEnable) { + _InitQueueReservedPage(Adapter); + _InitTxBufferBoundary(Adapter); + } + _InitQueuePriority(Adapter); + _InitPageBoundary(Adapter); + _InitTransferPageSize(Adapter); + + /* Get Rx PHY status in order to report RSSI and others. */ + _InitDriverInfoSize(Adapter, DRVINFO_SZ); + + _InitInterrupt(Adapter); + hal_init_macaddr23a(Adapter);/* set mac_address */ + _InitNetworkType(Adapter);/* set msr */ + _InitWMACSetting(Adapter); + _InitAdaptiveCtrl(Adapter); + _InitEDCA(Adapter); + _InitRateFallback(Adapter); + _InitRetryFunction(Adapter); + InitUsbAggregationSetting(Adapter); + _InitOperationMode(Adapter);/* todo */ + rtl8723a_InitBeaconParameters(Adapter); + + _InitHWLed(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK); + _BBTurnOnBlock(Adapter); + /* NicIFSetMacAddress(padapter, padapter->PermanentAddress); */ + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY); + invalidate_cam_all23a(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11); + /* 2010/12/17 MH We need to set TX power according to EFUSE content at first. */ + PHY_SetTxPowerLevel8723A(Adapter, pHalData->CurrentChannel); + + rtl8723a_InitAntenna_Selection(Adapter); + + /* HW SEQ CTRL */ + /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */ + rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF); + + /* */ + /* Disable BAR, suggested by Scott */ + /* 2010.04.09 add by hpfan */ + /* */ + rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff); + + if (pregistrypriv->wifi_spec) + rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0); + + /* Move by Neo for USB SS from above setp */ + _RfPowerSave(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); + /* 2010/08/26 MH Merge from 8192CE. */ + /* sherry masked that it has been done in _RfPowerSave */ + /* 20110927 */ + /* recovery for 8192cu and 9723Au 20111017 */ + if (pwrctrlpriv->rf_pwrstate == rf_on) { + if (pHalData->bIQKInitialized) { + rtl8723a_phy_iq_calibrate(Adapter, true); + } else { + rtl8723a_phy_iq_calibrate(Adapter, false); + pHalData->bIQKInitialized = true; + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK); + rtl8723a_odm_check_tx_power_tracking(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK); + rtl8723a_phy_lc_calibrate(Adapter); + +#ifdef CONFIG_8723AU_BT_COEXIST + rtl8723a_SingleDualAntennaDetection(Adapter); +#endif + } + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC21); + /* fixed USB interface interference issue */ + rtw_write8(Adapter, 0xfe40, 0xe0); + rtw_write8(Adapter, 0xfe41, 0x8d); + rtw_write8(Adapter, 0xfe42, 0x80); + rtw_write32(Adapter, 0x20c, 0xfd0320); + /* Solve too many protocol error on USB bus */ + if (!IS_81xxC_VENDOR_UMC_A_CUT(pHalData->VersionID)) { + /* 0xE6 = 0x94 */ + rtw_write8(Adapter, 0xFE40, 0xE6); + rtw_write8(Adapter, 0xFE41, 0x94); + rtw_write8(Adapter, 0xFE42, 0x80); + + /* 0xE0 = 0x19 */ + rtw_write8(Adapter, 0xFE40, 0xE0); + rtw_write8(Adapter, 0xFE41, 0x19); + rtw_write8(Adapter, 0xFE42, 0x80); + + /* 0xE5 = 0x91 */ + rtw_write8(Adapter, 0xFE40, 0xE5); + rtw_write8(Adapter, 0xFE41, 0x91); + rtw_write8(Adapter, 0xFE42, 0x80); + + /* 0xE2 = 0x81 */ + rtw_write8(Adapter, 0xFE40, 0xE2); + rtw_write8(Adapter, 0xFE41, 0x81); + rtw_write8(Adapter, 0xFE42, 0x80); + + } + +/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */ +/* _InitPABias(Adapter); */ + +#ifdef CONFIG_8723AU_BT_COEXIST + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BT_COEXIST); + /* Init BT hw config. */ + BT_InitHwConfig(Adapter); +#endif + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); + rtl8723a_InitHalDm(Adapter); + + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC31); + rtw_hal_set_hwreg23a(Adapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper); + + /* 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, but we need to fin root cause. */ + if (((rtw_read32(Adapter, rFPGA0_RFMOD) & 0xFF000000) != 0x83000000)) { + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT(24), 1); + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("%s: IQK fail recorver\n", __func__)); + } + + /* ack for xmit mgmt frames. */ + rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12)); + +exit: + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); + + DBG_8723A("%s in %dms\n", __func__, + jiffies_to_msecs(jiffies - init_start_time)); + return status; +} + +static void phy_SsPwrSwitch92CU(struct rtw_adapter *Adapter, + enum rt_rf_power_state eRFPowerState, + int bRegSSPwrLvl) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 value8; + u8 bytetmp; + + switch (eRFPowerState) { + case rf_on: + if (bRegSSPwrLvl == 1) { + /* 1. Enable MAC Clock. Can not be enabled now. */ + /* WriteXBYTE(REG_SYS_CLKR+1, + ReadXBYTE(REG_SYS_CLKR+1) | BIT(3)); */ + + /* 2. Force PWM, Enable SPS18_LDO_Marco_Block */ + rtw_write8(Adapter, REG_SPS0_CTRL, + rtw_read8(Adapter, REG_SPS0_CTRL) | + (BIT0|BIT3)); + + /* 3. restore BB, AFE control register. */ + /* RF */ + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x380038, 1); + else + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x38, 1); + PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 1); + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 0); + + /* AFE */ + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x63DB25A0); + else if (pHalData->rf_type == RF_1T1R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x631B25A0); + + /* 4. issue 3-wire command that RF set to Rx idle + mode. This is used to re-write the RX idle mode. */ + /* We can only prvide a usual value instead and then + HW will modify the value by itself. */ + PHY_SetRFReg(Adapter, RF_PATH_A, 0, + bRFRegOffsetMask, 0x32D95); + if (pHalData->rf_type == RF_2T2R) { + PHY_SetRFReg(Adapter, RF_PATH_B, 0, + bRFRegOffsetMask, 0x32D95); + } + } else { /* Level 2 or others. */ + /* h. AFE_PLL_CTRL 0x28[7:0] = 0x80 + disable AFE PLL */ + rtw_write8(Adapter, REG_AFE_PLL_CTRL, 0x81); + + /* i. AFE_XTAL_CTRL 0x24[15:0] = 0x880F + gated AFE DIG_CLOCK */ + rtw_write16(Adapter, REG_AFE_XTAL_CTRL, 0x800F); + mdelay(1); + + /* 2. Force PWM, Enable SPS18_LDO_Marco_Block */ + rtw_write8(Adapter, REG_SPS0_CTRL, + rtw_read8(Adapter, REG_SPS0_CTRL) | + (BIT0|BIT3)); + + /* 3. restore BB, AFE control register. */ + /* RF */ + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x380038, 1); + else + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x38, 1); + PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 1); + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 0); + + /* AFE */ + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, + bMaskDWord, 0x63DB25A0); + else if (pHalData->rf_type == RF_1T1R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, + bMaskDWord, 0x631B25A0); + + /* 4. issue 3-wire command that RF set to Rx idle + mode. This is used to re-write the RX idle mode. */ + /* We can only prvide a usual value instead and + then HW will modify the value by itself. */ + PHY_SetRFReg(Adapter, RF_PATH_A, 0, + bRFRegOffsetMask, 0x32D95); + if (pHalData->rf_type == RF_2T2R) { + PHY_SetRFReg(Adapter, RF_PATH_B, 0, + bRFRegOffsetMask, 0x32D95); + } + + /* 5. gated MAC Clock */ + bytetmp = rtw_read8(Adapter, REG_APSD_CTRL); + rtw_write8(Adapter, REG_APSD_CTRL, bytetmp & ~BIT6); + + mdelay(10); + + /* Set BB reset at first */ + rtw_write8(Adapter, REG_SYS_FUNC_EN, 0x17); /* 0x16 */ + + /* Enable TX */ + rtw_write8(Adapter, REG_TXPAUSE, 0x0); + } + break; + case rf_sleep: + case rf_off: + value8 = rtw_read8(Adapter, REG_SPS0_CTRL) ; + if (IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)) + value8 &= ~(BIT0); + else + value8 &= ~(BIT0|BIT3); + if (bRegSSPwrLvl == 1) { + RT_TRACE(_module_hal_init_c_, _drv_err_, ("SS LVL1\n")); + /* Disable RF and BB only for SelectSuspend. */ + + /* 1. Set BB/RF to shutdown. */ + /* (1) Reg878[5:3]= 0 RF rx_code for + preamble power saving */ + /* (2)Reg878[21:19]= 0 Turn off RF-B */ + /* (3) RegC04[7:4]= 0 Turn off all paths + for packet detection */ + /* (4) Reg800[1] = 1 enable preamble power + saving */ + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF0] = + PHY_QueryBBReg(Adapter, rFPGA0_XAB_RFParameter, + bMaskDWord); + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF1] = + PHY_QueryBBReg(Adapter, rOFDM0_TRxPathEnable, + bMaskDWord); + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF2] = + PHY_QueryBBReg(Adapter, rFPGA0_RFMOD, + bMaskDWord); + if (pHalData->rf_type == RF_2T2R) { + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x380038, 0); + } else if (pHalData->rf_type == RF_1T1R) { + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x38, 0); + } + PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 0); + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 1); + + /* 2 .AFE control register to power down. bit[30:22] */ + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_AFE0] = + PHY_QueryBBReg(Adapter, rRx_Wait_CCA, + bMaskDWord); + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x00DB25A0); + else if (pHalData->rf_type == RF_1T1R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x001B25A0); + + /* 3. issue 3-wire command that RF set to power down.*/ + PHY_SetRFReg(Adapter, RF_PATH_A, 0, bRFRegOffsetMask, 0); + if (pHalData->rf_type == RF_2T2R) + PHY_SetRFReg(Adapter, RF_PATH_B, 0, + bRFRegOffsetMask, 0); + + /* 4. Force PFM , disable SPS18_LDO_Marco_Block */ + rtw_write8(Adapter, REG_SPS0_CTRL, value8); + } else { /* Level 2 or others. */ + RT_TRACE(_module_hal_init_c_, _drv_err_, ("SS LVL2\n")); + { + u8 eRFPath = RF_PATH_A, value8 = 0; + rtw_write8(Adapter, REG_TXPAUSE, 0xFF); + PHY_SetRFReg(Adapter, + (enum RF_RADIO_PATH)eRFPath, + 0x0, bMaskByte0, 0x0); + value8 |= APSDOFF; + /* 0x40 */ + rtw_write8(Adapter, REG_APSD_CTRL, value8); + + /* After switch APSD, we need to delay + for stability */ + mdelay(10); + + /* Set BB reset at first */ + value8 = 0 ; + value8 |= (FEN_USBD | FEN_USBA | + FEN_BB_GLB_RSTn); + /* 0x16 */ + rtw_write8(Adapter, REG_SYS_FUNC_EN, value8); + } + + /* Disable RF and BB only for SelectSuspend. */ + + /* 1. Set BB/RF to shutdown. */ + /* (1) Reg878[5:3]= 0 RF rx_code for + preamble power saving */ + /* (2)Reg878[21:19]= 0 Turn off RF-B */ + /* (3) RegC04[7:4]= 0 Turn off all paths for + packet detection */ + /* (4) Reg800[1] = 1 enable preamble power + saving */ + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF0] = + PHY_QueryBBReg(Adapter, rFPGA0_XAB_RFParameter, + bMaskDWord); + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF1] = + PHY_QueryBBReg(Adapter, rOFDM0_TRxPathEnable, + bMaskDWord); + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF2] = + PHY_QueryBBReg(Adapter, rFPGA0_RFMOD, + bMaskDWord); + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x380038, 0); + else if (pHalData->rf_type == RF_1T1R) + PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, + 0x38, 0); + PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 0); + PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 1); + + /* 2 .AFE control register to power down. bit[30:22] */ + Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_AFE0] = + PHY_QueryBBReg(Adapter, rRx_Wait_CCA, + bMaskDWord); + if (pHalData->rf_type == RF_2T2R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x00DB25A0); + else if (pHalData->rf_type == RF_1T1R) + PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord, + 0x001B25A0); + + /* 3. issue 3-wire command that RF set to power down. */ + PHY_SetRFReg(Adapter, RF_PATH_A, 0, bRFRegOffsetMask, 0); + if (pHalData->rf_type == RF_2T2R) + PHY_SetRFReg(Adapter, RF_PATH_B, 0, + bRFRegOffsetMask, 0); + + /* 4. Force PFM , disable SPS18_LDO_Marco_Block */ + rtw_write8(Adapter, REG_SPS0_CTRL, value8); + + /* 2010/10/13 MH/Isaachsu exchange sequence. */ + /* h. AFE_PLL_CTRL 0x28[7:0] = 0x80 + disable AFE PLL */ + rtw_write8(Adapter, REG_AFE_PLL_CTRL, 0x80); + mdelay(1); + + /* i. AFE_XTAL_CTRL 0x24[15:0] = 0x880F + gated AFE DIG_CLOCK */ + rtw_write16(Adapter, REG_AFE_XTAL_CTRL, 0xA80F); + } + break; + default: + break; + } + +} /* phy_PowerSwitch92CU */ + +void _ps_open_RF23a(struct rtw_adapter *padapter) +{ + /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ + phy_SsPwrSwitch92CU(padapter, rf_on, 1); +} + +static void CardDisableRTL8723U(struct rtw_adapter *Adapter) +{ + u8 u1bTmp; + + DBG_8723A("CardDisableRTL8723U\n"); + /* USB-MF Card Disable Flow */ + /* 1. Run LPS WL RFOFF flow */ + HalPwrSeqCmdParsing23a(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_USB_MSK, rtl8723AU_enter_lps_flow); + + /* 2. 0x1F[7:0] = 0 turn off RF */ + rtw_write8(Adapter, REG_RF_CTRL, 0x00); + + /* ==== Reset digital sequence ====== */ + if ((rtw_read8(Adapter, REG_MCUFWDL)&BIT7) && + Adapter->bFWReady) /* 8051 RAM code */ + rtl8723a_FirmwareSelfReset(Adapter); + + /* Reset MCU. Suggested by Filen. 2011.01.26. by tynli. */ + u1bTmp = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); + rtw_write8(Adapter, REG_SYS_FUNC_EN+1, (u1bTmp & (~BIT2))); + + /* g. MCUFWDL 0x80[1:0]= 0 reset MCU ready status */ + rtw_write8(Adapter, REG_MCUFWDL, 0x00); + + /* ==== Reset digital sequence end ====== */ + /* Card disable power action flow */ + HalPwrSeqCmdParsing23a(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_USB_MSK, + rtl8723AU_card_disable_flow); + + /* Reset MCU IO Wrapper, added by Roger, 2011.08.30. */ + u1bTmp = rtw_read8(Adapter, REG_RSV_CTRL + 1); + rtw_write8(Adapter, REG_RSV_CTRL+1, (u1bTmp & (~BIT0))); + u1bTmp = rtw_read8(Adapter, REG_RSV_CTRL + 1); + rtw_write8(Adapter, REG_RSV_CTRL+1, u1bTmp | BIT0); + + /* 7. RSV_CTRL 0x1C[7:0] = 0x0E lock ISO/CLK/Power control register */ + rtw_write8(Adapter, REG_RSV_CTRL, 0x0e); +} + +static u32 rtl8723au_hal_deinit(struct rtw_adapter *padapter) +{ + DBG_8723A("==> %s\n", __func__); + +#ifdef CONFIG_8723AU_BT_COEXIST + BT_HaltProcess(padapter); +#endif + /* 2011/02/18 To Fix RU LNA power leakage problem. We need to + execute below below in Adapter init and halt sequence. + According to EEchou's opinion, we can enable the ability for all */ + /* IC. Accord to johnny's opinion, only RU need the support. */ + CardDisableRTL8723U(padapter); + + return _SUCCESS; +} + +static unsigned int rtl8723au_inirp_init(struct rtw_adapter *Adapter) +{ + u8 i; + struct recv_buf *precvbuf; + uint status; + struct intf_hdl *pintfhdl = &Adapter->iopriv.intf; + struct recv_priv *precvpriv = &Adapter->recvpriv; + u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + struct recv_buf *rbuf); + u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + _read_port = pintfhdl->io_ops._read_port; + + status = _SUCCESS; + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("===> usb_inirp_init\n")); + + precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR; + + /* issue Rx irp to receive data */ + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + for (i = 0; i < NR_RECVBUFF; i++) { + if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, precvbuf) == + false) { + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, + ("usb_rx_init: usb_read_port error\n")); + status = _FAIL; + goto exit; + } + precvbuf++; + precvpriv->free_recv_buf_queue_cnt--; + } + _read_interrupt = pintfhdl->io_ops._read_interrupt; + if (_read_interrupt(pintfhdl, RECV_INT_IN_ADDR) == false) { + RT_TRACE(_module_hci_hal_init_c_, _drv_err_, + ("usb_rx_init: usb_read_interrupt error\n")); + status = _FAIL; + } + pHalData->IntrMask[0] = rtw_read32(Adapter, REG_USB_HIMR); + MSG_8723A("pHalData->IntrMask = 0x%04x\n", pHalData->IntrMask[0]); + pHalData->IntrMask[0] |= UHIMR_C2HCMD|UHIMR_CPWM; + rtw_write32(Adapter, REG_USB_HIMR, pHalData->IntrMask[0]); +exit: + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("<=== usb_inirp_init\n")); + return status; +} + +static unsigned int rtl8723au_inirp_deinit(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("\n ===> usb_rx_deinit\n")); + rtw_read_port_cancel(Adapter); + pHalData->IntrMask[0] = rtw_read32(Adapter, REG_USB_HIMR); + MSG_8723A("%s pHalData->IntrMask = 0x%04x\n", __func__, + pHalData->IntrMask[0]); + pHalData->IntrMask[0] = 0x0; + rtw_write32(Adapter, REG_USB_HIMR, pHalData->IntrMask[0]); + RT_TRACE(_module_hci_hal_init_c_, _drv_info_, + ("\n <=== usb_rx_deinit\n")); + return _SUCCESS; +} + +static void _ReadBoardType(struct rtw_adapter *Adapter, u8 *PROMContent, + bool AutoloadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 boardType = BOARD_USB_DONGLE; + + if (AutoloadFail) { + if (IS_8723_SERIES(pHalData->VersionID)) + pHalData->rf_type = RF_1T1R; + else + pHalData->rf_type = RF_2T2R; + pHalData->BoardType = boardType; + return; + } + + boardType = PROMContent[EEPROM_NORMAL_BoardType]; + boardType &= BOARD_TYPE_NORMAL_MASK;/* bit[7:5] */ + boardType >>= 5; + + pHalData->BoardType = boardType; + MSG_8723A("_ReadBoardType(%x)\n", pHalData->BoardType); + + if (boardType == BOARD_USB_High_PA) + pHalData->ExternalPA = 1; +} + +static void _ReadLEDSetting(struct rtw_adapter *Adapter, u8 *PROMContent, + bool AutoloadFail) +{ + struct led_priv *pledpriv = &Adapter->ledpriv; + + pledpriv->LedStrategy = HW_LED; +} + +static void Hal_EfuseParsePIDVID_8723AU(struct rtw_adapter *pAdapter, + u8 *hwinfo, bool AutoLoadFail) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); + + if (AutoLoadFail) { + pHalData->EEPROMVID = 0; + pHalData->EEPROMPID = 0; + } else { + /* VID, PID */ + pHalData->EEPROMVID = + le16_to_cpu(*(u16 *)&hwinfo[EEPROM_VID_8723AU]); + pHalData->EEPROMPID = + le16_to_cpu(*(u16 *)&hwinfo[EEPROM_PID_8723AU]); + } + + MSG_8723A("EEPROM VID = 0x%4x\n", pHalData->EEPROMVID); + MSG_8723A("EEPROM PID = 0x%4x\n", pHalData->EEPROMPID); +} + +static void Hal_EfuseParseMACAddr_8723AU(struct rtw_adapter *padapter, + u8 *hwinfo, bool AutoLoadFail) +{ + u16 i; + u8 sMacAddr[ETH_ALEN] = {0x00, 0xE0, 0x4C, 0x87, 0x23, 0x00}; + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); + + if (AutoLoadFail) { + for (i = 0; i < 6; i++) + pEEPROM->mac_addr[i] = sMacAddr[i]; + } else { + /* Read Permanent MAC address */ + memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_8723AU], + ETH_ALEN); + } + + RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, + ("Hal_EfuseParseMACAddr_8723AU: Permanent Address =%02x:%02x:" + "%02x:%02x:%02x:%02x\n", + pEEPROM->mac_addr[0], pEEPROM->mac_addr[1], + pEEPROM->mac_addr[2], pEEPROM->mac_addr[3], + pEEPROM->mac_addr[4], pEEPROM->mac_addr[5])); +} + +static void readAdapterInfo(struct rtw_adapter *padapter) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); + /* struct hal_data_8723a * pHalData = GET_HAL_DATA(padapter); */ + u8 hwinfo[HWSET_MAX_SIZE]; + + Hal_InitPGData(padapter, hwinfo); + Hal_EfuseParseIDCode(padapter, hwinfo); + Hal_EfuseParsePIDVID_8723AU(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParseEEPROMVer(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParseMACAddr_8723AU(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParsetxpowerinfo_8723A(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + _ReadBoardType(padapter, hwinfo, pEEPROM->bautoload_fail_flag); + Hal_EfuseParseBTCoexistInfo_8723A(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + + rtl8723a_EfuseParseChnlPlan(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParseThermalMeter_8723A(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + _ReadLEDSetting(padapter, hwinfo, pEEPROM->bautoload_fail_flag); +/* _ReadRFSetting(Adapter, PROMContent, pEEPROM->bautoload_fail_flag); */ +/* _ReadPSSetting(Adapter, PROMContent, pEEPROM->bautoload_fail_flag); */ + Hal_EfuseParseAntennaDiversity(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + + Hal_EfuseParseEEPROMVer(padapter, hwinfo, pEEPROM->bautoload_fail_flag); + Hal_EfuseParseCustomerID(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParseRateIndicationOption(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + Hal_EfuseParseXtal_8723A(padapter, hwinfo, + pEEPROM->bautoload_fail_flag); + /* */ + /* The following part initialize some vars by PG info. */ + /* */ + Hal_InitChannelPlan23a(padapter); + + /* hal_CustomizedBehavior_8723U(Adapter); */ + +/* Adapter->bDongle = (PROMContent[EEPROM_EASY_REPLACEMENT] == 1)? 0: 1; */ + DBG_8723A("%s(): REPLACEMENT = %x\n", __func__, padapter->bDongle); +} + +static void _ReadPROMContent(struct rtw_adapter *Adapter) +{ + struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); + u8 eeValue; + + eeValue = rtw_read8(Adapter, REG_9346CR); + /* To check system boot selection. */ + pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false; + pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true; + + DBG_8723A("Boot from %s, Autoload %s !\n", + (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"), + (pEEPROM->bautoload_fail_flag ? "Fail" : "OK")); + + readAdapterInfo(Adapter); +} + +static void _ReadRFType(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + pHalData->rf_chip = RF_6052; +} + +static void _ReadSilmComboMode(struct rtw_adapter *Adapter) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + + pHalData->SlimComboDbg = false; /* Default is not debug mode. */ +} + +/* */ +/* Description: */ +/* We should set Efuse cell selection to WiFi cell in default. */ +/* */ +/* Assumption: */ +/* PASSIVE_LEVEL */ +/* */ +/* Added by Roger, 2010.11.23. */ +/* */ +static void hal_EfuseCellSel(struct rtw_adapter *Adapter) +{ + u32 value32; + + value32 = rtw_read32(Adapter, EFUSE_TEST); + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); + rtw_write32(Adapter, EFUSE_TEST, value32); +} + +static int _ReadAdapterInfo8723AU(struct rtw_adapter *Adapter) +{ + /* struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); */ + unsigned long start = jiffies; + + MSG_8723A("====> _ReadAdapterInfo8723AU\n"); + + hal_EfuseCellSel(Adapter); + + _ReadRFType(Adapter);/* rf_chip -> _InitRFType() */ + _ReadPROMContent(Adapter); + + /* 2010/10/25 MH THe function must be called after + borad_type & IC-Version recognize. */ + _ReadSilmComboMode(Adapter); + + /* MSG_8723A("%s()(done), rf_chip = 0x%x, rf_type = 0x%x\n", + __func__, pHalData->rf_chip, pHalData->rf_type); */ + + MSG_8723A("<==== _ReadAdapterInfo8723AU in %d ms\n", + jiffies_to_msecs(jiffies - start)); + + return _SUCCESS; +} + +static void ReadAdapterInfo8723AU(struct rtw_adapter *Adapter) +{ + /* Read EEPROM size before call any EEPROM function */ + Adapter->EepromAddressSize = GetEEPROMSize8723A(Adapter); + + _ReadAdapterInfo8723AU(Adapter); +} + +#define GPIO_DEBUG_PORT_NUM 0 +static void rtl8723au_trigger_gpio_0(struct rtw_adapter *padapter) +{ + u32 gpioctrl; + DBG_8723A("==> trigger_gpio_0...\n"); + rtw_write16_async(padapter, REG_GPIO_PIN_CTRL, 0); + rtw_write8_async(padapter, REG_GPIO_PIN_CTRL+2, 0xFF); + gpioctrl = (BIT(GPIO_DEBUG_PORT_NUM) << 24)| + (BIT(GPIO_DEBUG_PORT_NUM) << 16); + rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl); + gpioctrl |= (BIT(GPIO_DEBUG_PORT_NUM)<<8); + rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl); + DBG_8723A("<=== trigger_gpio_0...\n"); +} + +/* + * If variable not handled here, + * some variables will be processed in SetHwReg8723A() + */ +static void SetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val) +{ + switch (variable) { + case HW_VAR_RXDMA_AGG_PG_TH: + break; + case HW_VAR_SET_RPWM: + rtl8723a_set_rpwm(Adapter, *val); + break; + case HW_VAR_TRIGGER_GPIO_0: + rtl8723au_trigger_gpio_0(Adapter); + break; + default: + SetHwReg8723A(Adapter, variable, val); + break; + } + +} + +/* + * If variable not handled here, + * some variables will be processed in GetHwReg8723A() + */ +static void GetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val) +{ + GetHwReg8723A(Adapter, variable, val); +} + +/* */ +/* Description: */ +/* Query setting of specified variable. */ +/* */ +static u8 GetHalDefVar8192CUsb(struct rtw_adapter *Adapter, + enum hal_def_variable eVariable, void *pValue) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 bResult = _SUCCESS; + + switch (eVariable) { + case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: + *((int *)pValue) = pHalData->dmpriv.UndecoratedSmoothedPWDB; + break; + case HAL_DEF_IS_SUPPORT_ANT_DIV: + break; + case HAL_DEF_CURRENT_ANTENNA: + break; + case HAL_DEF_DRVINFO_SZ: + *((u32 *)pValue) = DRVINFO_SZ; + break; + case HAL_DEF_MAX_RECVBUF_SZ: + *((u32 *)pValue) = MAX_RECVBUF_SZ; + break; + case HAL_DEF_RX_PACKET_OFFSET: + *((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ; + break; + case HAL_DEF_DBG_DUMP_RXPKT: + *((u8 *)pValue) = pHalData->bDumpRxPkt; + break; + case HAL_DEF_DBG_DM_FUNC: + *((u32 *)pValue) = pHalData->odmpriv.SupportAbility; + break; + case HW_VAR_MAX_RX_AMPDU_FACTOR: + *((u32 *)pValue) = IEEE80211_HT_MAX_AMPDU_64K; + break; + case HW_DEF_ODM_DBG_FLAG: + { + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + printk("pDM_Odm->DebugComponents = 0x%llx\n", + pDM_Odm->DebugComponents); + } + break; + default: + /* RT_TRACE(COMP_INIT, DBG_WARNING, ("GetHalDefVar8192CUsb(): " + "Unkown variable: %d!\n", eVariable)); */ + bResult = _FAIL; + break; + } + + return bResult; +} + +/* Change default setting of specified variable. */ +static u8 SetHalDefVar8192CUsb(struct rtw_adapter *Adapter, + enum hal_def_variable eVariable, void *pValue) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 bResult = _SUCCESS; + + switch (eVariable) { + case HAL_DEF_DBG_DUMP_RXPKT: + pHalData->bDumpRxPkt = *((u8 *)pValue); + break; + case HAL_DEF_DBG_DM_FUNC: + { + u8 dm_func = *((u8 *)pValue); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dm_odm_t *podmpriv = &pHalData->odmpriv; + + if (dm_func == 0) { /* disable all dynamic func */ + podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; + DBG_8723A("==> Disable all dynamic function...\n"); + } else if (dm_func == 1) {/* disable DIG */ + podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); + DBG_8723A("==> Disable DIG...\n"); + } else if (dm_func == 2) {/* disable High power */ + podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); + } else if (dm_func == 3) {/* disable tx power tracking */ + podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); + DBG_8723A("==> Disable tx power tracking...\n"); + } else if (dm_func == 4) {/* disable BT coexistence */ + pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT); + } else if (dm_func == 5) {/* disable antenna diversity */ + podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); + } else if (dm_func == 6) {/* turn on all dynamic func */ + if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) { + struct dig_t *pDigTable = + &podmpriv->DM_DigTable; + pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50); + } + pdmpriv->DMFlag |= DYNAMIC_FUNC_BT; + podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; + DBG_8723A("==> Turn on all dynamic function...\n"); + } + } + break; + case HW_DEF_FA_CNT_DUMP: + { + u8 bRSSIDump = *((u8 *)pValue); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + if (bRSSIDump) + pDM_Odm->DebugComponents = ODM_COMP_DIG|ODM_COMP_FA_CNT; + else + pDM_Odm->DebugComponents = 0; + } + break; + case HW_DEF_ODM_DBG_FLAG: + { + u64 DebugComponents = *((u64 *)pValue); + struct dm_odm_t *pDM_Odm = &pHalData->odmpriv; + pDM_Odm->DebugComponents = DebugComponents; + } + break; + default: + /* RT_TRACE(COMP_INIT, DBG_TRACE, ("SetHalDefVar819xUsb(): " + "Unkown variable: %d!\n", eVariable)); */ + bResult = _FAIL; + break; + } + + return bResult; +} + +static void UpdateHalRAMask8192CUsb(struct rtw_adapter *padapter, + u32 mac_id, u8 rssi_level) +{ + u8 init_rate = 0; + u8 networkType, raid; + u32 mask, rate_bitmap; + u8 shortGIrate = false; + int supportRateNum = 0; + struct sta_info *psta; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; + + if (mac_id >= NUM_STA) /* CAM_SIZE */ + return; + + psta = pmlmeinfo->FW_sta_info[mac_id].psta; + if (psta == NULL) + return; + + switch (mac_id) { + case 0:/* for infra mode */ + supportRateNum = + rtw_get_rateset_len23a(cur_network->SupportedRates); + networkType = judge_network_type23a(padapter, + cur_network->SupportedRates, + supportRateNum) & 0xf; + /* pmlmeext->cur_wireless_mode = networkType; */ + raid = networktype_to_raid23a(networkType); + + mask = update_supported_rate23a(cur_network->SupportedRates, + supportRateNum); + mask |= (pmlmeinfo->HT_enable) ? + update_MSC_rate23a(&pmlmeinfo->HT_caps) : 0; + + if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps)) + shortGIrate = true; + break; + + case 1:/* for broadcast/multicast */ + supportRateNum = rtw_get_rateset_len23a( + pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + if (pmlmeext->cur_wireless_mode & WIRELESS_11B) + networkType = WIRELESS_11B; + else + networkType = WIRELESS_11G; + raid = networktype_to_raid23a(networkType); + + mask = update_basic_rate23a(cur_network->SupportedRates, + supportRateNum); + break; + + default: /* for each sta in IBSS */ + supportRateNum = rtw_get_rateset_len23a( + pmlmeinfo->FW_sta_info[mac_id].SupportedRates); + networkType = judge_network_type23a(padapter, + pmlmeinfo->FW_sta_info[mac_id].SupportedRates, + supportRateNum) & 0xf; + /* pmlmeext->cur_wireless_mode = networkType; */ + raid = networktype_to_raid23a(networkType); + + mask = update_supported_rate23a(cur_network->SupportedRates, + supportRateNum); + + /* todo: support HT in IBSS */ + break; + } + + /* mask &= 0x0fffffff; */ + rate_bitmap = 0x0fffffff; + rate_bitmap = ODM_Get_Rate_Bitmap23a(&pHalData->odmpriv, + mac_id, mask, rssi_level); + printk(KERN_DEBUG "%s => mac_id:%d, networkType:0x%02x, " + "mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", + __func__, + mac_id, networkType, mask, rssi_level, rate_bitmap); + + mask &= rate_bitmap; + mask |= ((raid<<28)&0xf0000000); + + init_rate = get_highest_rate_idx23a(mask)&0x3f; + + if (pHalData->fw_ractrl == true) { + u8 arg = 0; + + /* arg = (cam_idx-4)&0x1f;MACID */ + arg = mac_id&0x1f;/* MACID */ + + arg |= BIT(7); + + if (shortGIrate == true) + arg |= BIT(5); + + DBG_8723A("update raid entry, mask = 0x%x, arg = 0x%x\n", + mask, arg); + + rtl8723a_set_raid_cmd(padapter, mask, arg); + } else { + if (shortGIrate == true) + init_rate |= BIT(6); + + rtw_write8(padapter, (REG_INIDATA_RATE_SEL+mac_id), init_rate); + } + + /* set ra_id */ + psta->raid = raid; + psta->init_rate = init_rate; + + /* set correct initial date rate for each mac_id */ + pdmpriv->INIDATA_RATE[mac_id] = init_rate; +} + +static void rtl8723au_init_default_value(struct rtw_adapter *padapter) +{ + rtl8723a_init_default_value(padapter); +} + +static u8 rtl8192cu_ps_func(struct rtw_adapter *Adapter, + enum hal_intf_ps_func efunc_id, u8 *val) +{ + return true; +} + +int rtl8723au_set_hal_ops(struct rtw_adapter *padapter) +{ + struct hal_ops *pHalFunc = &padapter->HalFunc; + + padapter->HalData = kzalloc(sizeof(struct hal_data_8723a), GFP_KERNEL); + if (!padapter->HalData) { + DBG_8723A("cannot alloc memory for HAL DATA\n"); + return -ENOMEM; + } + padapter->hal_data_sz = sizeof(struct hal_data_8723a); + + pHalFunc->hal_init = &rtl8723au_hal_init; + pHalFunc->hal_deinit = &rtl8723au_hal_deinit; + + pHalFunc->inirp_init = &rtl8723au_inirp_init; + pHalFunc->inirp_deinit = &rtl8723au_inirp_deinit; + + pHalFunc->init_xmit_priv = &rtl8723au_init_xmit_priv; + pHalFunc->free_xmit_priv = &rtl8723au_free_xmit_priv; + + pHalFunc->init_recv_priv = &rtl8723au_init_recv_priv; + pHalFunc->free_recv_priv = &rtl8723au_free_recv_priv; + pHalFunc->InitSwLeds = NULL; + pHalFunc->DeInitSwLeds = NULL; + + pHalFunc->init_default_value = &rtl8723au_init_default_value; + pHalFunc->intf_chip_configure = &rtl8723au_interface_configure; + pHalFunc->read_adapter_info = &ReadAdapterInfo8723AU; + pHalFunc->SetHwRegHandler = &SetHwReg8723AU; + pHalFunc->GetHwRegHandler = &GetHwReg8723AU; + pHalFunc->GetHalDefVarHandler = &GetHalDefVar8192CUsb; + pHalFunc->SetHalDefVarHandler = &SetHalDefVar8192CUsb; + pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8192CUsb; + pHalFunc->hal_xmit = &rtl8723au_hal_xmit; + pHalFunc->mgnt_xmit = &rtl8723au_mgnt_xmit; + pHalFunc->hal_xmitframe_enqueue = &rtl8723au_hal_xmitframe_enqueue; + pHalFunc->interface_ps_func = &rtl8192cu_ps_func; + rtl8723a_set_hal_ops(pHalFunc); + return 0; +} diff --git a/drivers/staging/rtl8723au/hal/usb_ops_linux.c b/drivers/staging/rtl8723au/hal/usb_ops_linux.c new file mode 100644 index 000000000000..0311cdf77ff1 --- /dev/null +++ b/drivers/staging/rtl8723au/hal/usb_ops_linux.c @@ -0,0 +1,848 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _HCI_OPS_OS_C_ + +#include +#include +#include +#include +#include +#include +#include + +static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype) +{ + struct rtw_adapter *padapter = pintfhdl->padapter ; + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct usb_device *udev = pdvobjpriv->pusbdev; + + unsigned int pipe; + int status = 0; + u8 reqtype; + u8 *pIo_buf; + int vendorreq_times = 0; + + if ((padapter->bSurpriseRemoved) || (padapter->pwrctrlpriv.pnp_bstop_trx)) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usbctrl_vendorreq:(padapter->bSurpriseRemoved||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); + status = -EPERM; + goto exit; + } + + if (len > MAX_VENDOR_REQ_CMD_SIZE) { + DBG_8723A("[%s] Buffer len error , vendor request failed\n", __FUNCTION__); + status = -EINVAL; + goto exit; + } + + mutex_lock(&pdvobjpriv->usb_vendor_req_mutex); + + /* Acquire IO memory for vendorreq */ + pIo_buf = pdvobjpriv->usb_vendor_req_buf; + + if (pIo_buf == NULL) { + DBG_8723A("[%s] pIo_buf == NULL \n", __FUNCTION__); + status = -ENOMEM; + goto release_mutex; + } + + while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { + memset(pIo_buf, 0, len); + + if (requesttype == 0x01) { + pipe = usb_rcvctrlpipe(udev, 0);/* read_in */ + reqtype = REALTEK_USB_VENQT_READ; + } else { + pipe = usb_sndctrlpipe(udev, 0);/* write_out */ + reqtype = REALTEK_USB_VENQT_WRITE; + memcpy(pIo_buf, pdata, len); + } + + status = rtw_usb_control_msg(udev, pipe, request, reqtype, + value, index, pIo_buf, len, + RTW_USB_CONTROL_MSG_TIMEOUT); + + if (status == len) { /* Success this control transfer. */ + rtw_reset_continual_urb_error(pdvobjpriv); + if (requesttype == 0x01) { + /* For Control read transfer, we have to copy + * the read data from pIo_buf to pdata. + */ + memcpy(pdata, pIo_buf, len); + } + } else { /* error cases */ + DBG_8723A("reg 0x%x, usb %s %u fail, status:%d value =" + " 0x%x, vendorreq_times:%d\n", + value, (requesttype == 0x01) ? "read" : "write", + len, status, *(u32 *)pdata, vendorreq_times); + + if (status < 0) { + if (status == (-ESHUTDOWN) || status == -ENODEV) { + padapter->bSurpriseRemoved = true; + } else { + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL; + } + } else { /* status != len && status >= 0 */ + if (status > 0) { + if (requesttype == 0x01) { + /* For Control read transfer, we have to copy + * the read data from pIo_buf to pdata. + */ + memcpy(pdata, pIo_buf, len); + } + } + } + + if (rtw_inc_and_chk_continual_urb_error(pdvobjpriv)) { + padapter->bSurpriseRemoved = true; + break; + } + + } + + /* firmware download is checksumed, don't retry */ + if ((value >= FW_8723A_START_ADDRESS && value <= FW_8723A_END_ADDRESS) || status == len) + break; + } + +release_mutex: + mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex); +exit: + return status; +} + +static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 data = 0; + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 1; + + usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + + return data; +} + +static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u16 data = 0; + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 2; + + usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + + return data; +} + +static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data = 0; + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 4; + + usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + + return data; +} + +static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 data; + int ret; + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 1; + + data = val; + + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + + return ret; +} + +static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u16 data; + int ret; + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 2; + + data = val; + + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + return ret; +} + +static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + int ret; + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = 4; + data = val; + + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); + + return ret; +} + +static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0}; + int ret; + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr&0x0000ffff); + len = length; + memcpy(buf, pdata, len); + + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype); + + return ret; +} + +/* + * Description: + * Recognize the interrupt content by reading the interrupt + * register or content and masking interrupt mask (IMR) + * if it is our NIC's interrupt. After recognizing, we may clear + * the all interrupts (ISR). + * Arguments: + * [in] Adapter - + * The adapter context. + * [in] pContent - + * Under PCI interface, this field is ignord. + * Under USB interface, the content is the interrupt + * content pointer. + * Under SDIO interface, this is the interrupt type which + * is Local interrupt or system interrupt. + * [in] ContentLen - + * The length in byte of pContent. + * Return: + * If any interrupt matches the mask (IMR), return true, and + * return false otherwise. + */ +static bool +InterruptRecognized8723AU(struct rtw_adapter *Adapter, void *pContent, + u32 ContentLen) +{ + struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); + u8 *buffer = (u8 *)pContent; + struct reportpwrstate_parm report; + + memcpy(&pHalData->IntArray[0], &buffer[USB_INTR_CONTENT_HISR_OFFSET], + 4); + pHalData->IntArray[0] &= pHalData->IntrMask[0]; + + /* For HISR extension. Added by tynli. 2009.10.07. */ + memcpy(&pHalData->IntArray[1], + &buffer[USB_INTR_CONTENT_HISRE_OFFSET], 4); + pHalData->IntArray[1] &= pHalData->IntrMask[1]; + + /* We sholud remove this function later because DDK suggest + * not to executing too many operations in MPISR */ + + memcpy(&report.state, &buffer[USB_INTR_CPWM_OFFSET], 1); + + return ((pHalData->IntArray[0])&pHalData->IntrMask[0]) != 0 || + ((pHalData->IntArray[1])&pHalData->IntrMask[1]) != 0; +} + +static void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs) +{ + int err; + struct rtw_adapter *padapter = (struct rtw_adapter *)purb->context; + + if (padapter->bSurpriseRemoved || padapter->bDriverStopped || + padapter->bReadPortCancel) { + DBG_8723A("%s() RX Warning! bDriverStopped(%d) OR " + "bSurpriseRemoved(%d) bReadPortCancel(%d)\n", + __FUNCTION__, padapter->bDriverStopped, + padapter->bSurpriseRemoved, + padapter->bReadPortCancel); + return; + } + + if (purb->status == 0) { + struct c2h_evt_hdr *c2h_evt; + + c2h_evt = (struct c2h_evt_hdr *)purb->transfer_buffer; + + if (purb->actual_length > USB_INTR_CONTENT_LENGTH) { + DBG_8723A("usb_read_interrupt_complete: purb->actual_" + "length > USB_INTR_CONTENT_LENGTH\n"); + goto urb_submit; + } + + InterruptRecognized8723AU(padapter, purb->transfer_buffer, + purb->actual_length); + + if (c2h_evt_exist(c2h_evt)) { + if (c2h_id_filter_ccx_8723a(c2h_evt->id)) { + /* Handle CCX report here */ + handle_txrpt_ccx_8723a(padapter, (void *)(c2h_evt->payload)); + /* Replace with special pointer to + trigger c2h_evt_clear23a */ + if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue, + (void *)&padapter->evtpriv) != + _SUCCESS) + DBG_8723A("%s rtw_cbuf_push23a fail\n", + __func__); + schedule_work(&padapter->evtpriv.c2h_wk); + } else if ((c2h_evt = (struct c2h_evt_hdr *) + kmalloc(16, GFP_ATOMIC))) { + memcpy(c2h_evt, purb->transfer_buffer, 16); + if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue, + (void *)c2h_evt) != _SUCCESS) + DBG_8723A("%s rtw_cbuf_push23a fail\n", + __func__); + schedule_work(&padapter->evtpriv.c2h_wk); + } else { + /* Error handling for malloc fail */ + if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue, + (void *)NULL) != _SUCCESS) + DBG_8723A("%s rtw_cbuf_push23a fail\n", + __func__); + schedule_work(&padapter->evtpriv.c2h_wk); + } + } + +urb_submit: + err = usb_submit_urb(purb, GFP_ATOMIC); + if (err && (err != -EPERM)) { + DBG_8723A("cannot submit interrupt in-token(err = " + "0x%08x), urb_status = %d\n", + err, purb->status); + } + } else { + DBG_8723A("###=> usb_read_interrupt_complete => urb " + "status(%d)\n", purb->status); + + switch (purb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete:bSurpriseRemoved =" + "true\n")); + /* Fall Through here */ + case -ENOENT: + padapter->bDriverStopped = true; + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete:bDriverStopped =" + "true\n")); + break; + case -EPROTO: + break; + case -EINPROGRESS: + DBG_8723A("ERROR: URB IS IN PROGRESS!/n"); + break; + default: + break; + } + } +} + +static u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr) +{ + int err; + unsigned int pipe; + u32 ret = _SUCCESS; + struct rtw_adapter *adapter = pintfhdl->padapter; + struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); + struct recv_priv *precvpriv = &adapter->recvpriv; + struct usb_device *pusbd = pdvobj->pusbdev; + + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl23a(pdvobj, addr); + + usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe, + precvpriv->int_in_buf, USB_INTR_CONTENT_LENGTH, + usb_read_interrupt_complete, adapter, 1); + + err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC); + if (err && (err != -EPERM)) { + DBG_8723A("cannot submit interrupt in-token(err = 0x%08x)," + "urb_status = %d\n", err, + precvpriv->int_in_urb->status); + ret = _FAIL; + } + + return ret; +} + +static int recvbuf2recvframe(struct rtw_adapter *padapter, struct sk_buff *pskb) +{ + u8 *pbuf; + u8 shift_sz = 0; + u16 pkt_cnt; + u32 pkt_offset, skb_len, alloc_sz; + s32 transfer_len; + struct recv_stat *prxstat; + struct phy_stat *pphy_info = NULL; + struct sk_buff *pkt_copy = NULL; + struct recv_frame *precvframe = NULL; + struct rx_pkt_attrib *pattrib = NULL; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct rtw_queue *pfree_recv_queue = &precvpriv->free_recv_queue; + + transfer_len = (s32)pskb->len; + pbuf = pskb->data; + + prxstat = (struct recv_stat *)pbuf; + pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; + + do { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("recvbuf2recvframe: rxdesc = offsset 0:0x%08x, " + "4:0x%08x, 8:0x%08x, C:0x%08x\n", prxstat->rxdw0, + prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4)); + + prxstat = (struct recv_stat *)pbuf; + + precvframe = rtw_alloc_recvframe23a(pfree_recv_queue); + if (!precvframe) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recvbuf2recvframe: precvframe == NULL\n")); + DBG_8723A("%s()-%d: rtw_alloc_recvframe23a() failed! RX " + "Drop!\n", __FUNCTION__, __LINE__); + goto _exit_recvbuf2recvframe; + } + + INIT_LIST_HEAD(&precvframe->list); + + update_recvframe_attrib(precvframe, prxstat); + + pattrib = &precvframe->attrib; + + if (pattrib->crc_err) { + DBG_8723A("%s()-%d: RX Warning! rx CRC ERROR !!\n", + __FUNCTION__, __LINE__); + rtw_free_recvframe23a(precvframe, pfree_recv_queue); + goto _exit_recvbuf2recvframe; + } + + pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + + pattrib->shift_sz + pattrib->pkt_len; + + if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) { + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, + ("recvbuf2recvframe: pkt_len<= 0\n")); + DBG_8723A("%s()-%d: RX Warning!\n", + __FUNCTION__, __LINE__); + rtw_free_recvframe23a(precvframe, pfree_recv_queue); + goto _exit_recvbuf2recvframe; + } + + /* Modified by Albert 20101213 */ + /* For 8 bytes IP header alignment. */ + /* Qos data, wireless lan header length is 26 */ + if (pattrib->qos) { + shift_sz = 6; + } else { + shift_sz = 0; + } + + skb_len = pattrib->pkt_len; + + /* for first fragment packet, driver need allocate + * 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. + * modify alloc_sz for recvive crc error packet + * by thomas 2011-06-02 */ + if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { + /* alloc_sz = 1664; 1664 is 128 alignment. */ + if (skb_len <= 1650) + alloc_sz = 1664; + else + alloc_sz = skb_len + 14; + } else { + alloc_sz = skb_len; + /* 6 is for IP header 8 bytes alignment in QoS packet case. */ + /* 8 is for skb->data 4 bytes alignment. */ + alloc_sz += 14; + } + + pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz); + if (pkt_copy) { + pkt_copy->dev = padapter->pnetdev; + precvframe->pkt = pkt_copy; + skb_reserve(pkt_copy, 8 - ((unsigned long)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */ + /*force ip_hdr at 8-byte alignment address according to shift_sz. */ + skb_reserve(pkt_copy, shift_sz); + memcpy(pkt_copy->data, (pbuf + pattrib->shift_sz + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len); + skb_put(pkt_copy, skb_len); + } else { + if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { + DBG_8723A("recvbuf2recvframe: alloc_skb fail, " + "drop frag frame \n"); + rtw_free_recvframe23a(precvframe, + pfree_recv_queue); + goto _exit_recvbuf2recvframe; + } + + precvframe->pkt = skb_clone(pskb, GFP_ATOMIC); + if (!precvframe->pkt) { + DBG_8723A("recvbuf2recvframe: skb_clone " + "fail\n"); + rtw_free_recvframe23a(precvframe, + pfree_recv_queue); + goto _exit_recvbuf2recvframe; + } + } + + if (pattrib->physt) { + pphy_info = (struct phy_stat *)(pbuf + RXDESC_OFFSET); + update_recvframe_phyinfo(precvframe, pphy_info); + } + + if (rtw_recv_entry23a(precvframe) != _SUCCESS) + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, + ("recvbuf2recvframe: rtw_recv_entry23a" + "(precvframe) != _SUCCESS\n")); + + pkt_cnt--; + transfer_len -= pkt_offset; + pbuf += pkt_offset; + precvframe = NULL; + pkt_copy = NULL; + + if (transfer_len > 0 && pkt_cnt == 0) + pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; + + } while ((transfer_len > 0) && (pkt_cnt > 0)); + +_exit_recvbuf2recvframe: + + return _SUCCESS; +} + +void rtl8723au_recv_tasklet(void *priv) +{ + struct sk_buff *pskb; + struct rtw_adapter *padapter = (struct rtw_adapter *)priv; + struct recv_priv *precvpriv = &padapter->recvpriv; + + while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { + if ((padapter->bDriverStopped) || + (padapter->bSurpriseRemoved)) { + DBG_8723A("recv_tasklet => bDriverStopped or " + "bSurpriseRemoved \n"); + dev_kfree_skb_any(pskb); + break; + } + + recvbuf2recvframe(padapter, pskb); + skb_reset_tail_pointer(pskb); + + pskb->len = 0; + + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + } +} + +static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) +{ + struct recv_buf *precvbuf = (struct recv_buf *)purb->context; + struct rtw_adapter *padapter = (struct rtw_adapter *)precvbuf->adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct hal_data_8723a *pHalData; + + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete!!!\n")); + + precvpriv->rx_pending_cnt--; + + if (padapter->bSurpriseRemoved || padapter->bDriverStopped || + padapter->bReadPortCancel) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete:bDriverStopped(%d) OR " + "bSurpriseRemoved(%d)\n", padapter->bDriverStopped, + padapter->bSurpriseRemoved)); + + DBG_8723A("%s()-%d: RX Warning! bDriverStopped(%d) OR " + "bSurpriseRemoved(%d) bReadPortCancel(%d)\n", + __FUNCTION__, __LINE__, padapter->bDriverStopped, + padapter->bSurpriseRemoved, padapter->bReadPortCancel); + return; + } + + if (purb->status == 0) { + if ((purb->actual_length > MAX_RECVBUF_SZ) || + (purb->actual_length < RXDESC_SIZE)) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete: (purb->actual_" + "length > MAX_RECVBUF_SZ) || (purb->actual_" + "length < RXDESC_SIZE)\n")); + rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, + precvbuf); + DBG_8723A("%s()-%d: RX Warning!\n", + __FUNCTION__, __LINE__); + } else { + rtw_reset_continual_urb_error( + adapter_to_dvobj(padapter)); + + skb_put(precvbuf->pskb, purb->actual_length); + skb_queue_tail(&precvpriv->rx_skb_queue, + precvbuf->pskb); + + if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1) + tasklet_schedule(&precvpriv->recv_tasklet); + + precvbuf->pskb = NULL; + rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, + precvbuf); + } + } else { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete : purb->status(%d) != 0 \n", + purb->status)); + skb_put(precvbuf->pskb, purb->actual_length); + precvbuf->pskb = NULL; + + DBG_8723A("###=> usb_read_port_complete => urb status(%d)\n", + purb->status); + + if (rtw_inc_and_chk_continual_urb_error( + adapter_to_dvobj(padapter))) { + padapter->bSurpriseRemoved = true; + } + + switch (purb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete:bSurprise" + "Removed = true\n")); + /* Intentional fall through here */ + case -ENOENT: + padapter->bDriverStopped = true; + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port_complete:" + "bDriverStopped = true\n")); + break; + case -EPROTO: + case -EOVERFLOW: + pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.Wifi_Error_Status = + USB_READ_PORT_FAIL; + rtw_read_port(padapter, precvpriv->ff_hwaddr, + 0, precvbuf); + break; + case -EINPROGRESS: + DBG_8723A("ERROR: URB IS IN PROGRESS!/n"); + break; + default: + break; + } + + } +} + +static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + struct recv_buf *precvbuf) +{ + int err; + unsigned int pipe; + unsigned long tmpaddr = 0; + unsigned long alignment = 0; + u32 ret = _SUCCESS; + struct urb *purb = NULL; + struct rtw_adapter *adapter = pintfhdl->padapter; + struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); + struct recv_priv *precvpriv = &adapter->recvpriv; + struct usb_device *pusbd = pdvobj->pusbdev; + + if (adapter->bDriverStopped || adapter->bSurpriseRemoved || + adapter->pwrctrlpriv.pnp_bstop_trx) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port:(padapter->bDriverStopped ||" + "padapter->bSurpriseRemoved ||adapter->" + "pwrctrlpriv.pnp_bstop_trx)!!!\n")); + return _FAIL; + } + + if (!precvbuf) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_read_port:precvbuf == NULL\n")); + return _FAIL; + } + + if (!precvbuf->pskb) + precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); + + rtl8723au_init_recvbuf(adapter, precvbuf); + + /* re-assign for linux based on skb */ + if (!precvbuf->pskb) { + precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); + if (precvbuf->pskb == NULL) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n")); + return _FAIL; + } + + tmpaddr = (unsigned long)precvbuf->pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); + skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); + } + + precvpriv->rx_pending_cnt++; + + purb = precvbuf->purb; + + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl23a(pdvobj, addr); + + usb_fill_bulk_urb(purb, pusbd, pipe, precvbuf->pskb->data, + MAX_RECVBUF_SZ, usb_read_port_complete, + precvbuf);/* context is precvbuf */ + + err = usb_submit_urb(purb, GFP_ATOMIC); + if ((err) && (err != -EPERM)) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("cannot submit rx in-token(err = 0x%.8x), URB_STATUS " + "= 0x%.8x", err, purb->status)); + DBG_8723A("cannot submit rx in-token(err = 0x%08x), urb_status " + "= %d\n", err, purb->status); + ret = _FAIL; + } + return ret; +} + +void rtl8723au_xmit_tasklet(void *priv) +{ + int ret = false; + struct rtw_adapter *padapter = (struct rtw_adapter *)priv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY)) + return; + + while (1) { + if ((padapter->bDriverStopped) || + (padapter->bSurpriseRemoved) || + (padapter->bWritePortCancel)) { + DBG_8723A("xmit_tasklet => bDriverStopped or " + "bSurpriseRemoved or bWritePortCancel\n"); + break; + } + + ret = rtl8723au_xmitframe_complete(padapter, pxmitpriv, NULL); + + if (!ret) + break; + } +} + +void rtl8723au_set_intf_ops(struct _io_ops *pops) +{ + + memset((u8 *)pops, 0, sizeof(struct _io_ops)); + + pops->_read8 = &usb_read8; + pops->_read16 = &usb_read16; + pops->_read32 = &usb_read32; + pops->_read_mem = &usb_read_mem23a; + pops->_read_port = &usb_read_port; + + pops->_write8 = &usb_write8; + pops->_write16 = &usb_write16; + pops->_write32 = &usb_write32; + pops->_writeN = &usb_writeN; + + pops->_write_mem = &usb_write_mem23a; + pops->_write_port = &usb_write_port23a; + + pops->_read_port_cancel = &usb_read_port_cancel23a; + pops->_write_port_cancel = &usb_write_port23a_cancel; + + pops->_read_interrupt = &usb_read_interrupt; +} + +void rtl8723au_set_hw_type(struct rtw_adapter *padapter) +{ + padapter->chip_type = RTL8723A; + padapter->HardwareType = HARDWARE_TYPE_RTL8723AU; + DBG_8723A("CHIP TYPE: RTL8723A\n"); +} -- cgit v1.2.3 From b1925ad84625302fac456d8671b2acafcabf57f5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:40 -0500 Subject: staging: r8723au: Add source files for new driver - part 3 The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets. A driver for it has been available in a GitHub repo for several months. This commit contains the third part of source files. The source is arbitrarily split to avoid E-mail files that are too large. Jes Sorensen at RedHat has made many improvements to the vendor code, and he has been doing the testing. I do not have access to this device. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | 4501 +++++++++++++++++++++ drivers/staging/rtl8723au/os_dep/mlme_linux.c | 187 + drivers/staging/rtl8723au/os_dep/os_intfs.c | 970 +++++ drivers/staging/rtl8723au/os_dep/osdep_service.c | 429 ++ drivers/staging/rtl8723au/os_dep/recv_linux.c | 225 + drivers/staging/rtl8723au/os_dep/usb_intf.c | 836 ++++ drivers/staging/rtl8723au/os_dep/usb_ops_linux.c | 283 ++ drivers/staging/rtl8723au/os_dep/xmit_linux.c | 195 + 8 files changed, 7626 insertions(+) create mode 100644 drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c create mode 100644 drivers/staging/rtl8723au/os_dep/mlme_linux.c create mode 100644 drivers/staging/rtl8723au/os_dep/os_intfs.c create mode 100644 drivers/staging/rtl8723au/os_dep/osdep_service.c create mode 100644 drivers/staging/rtl8723au/os_dep/recv_linux.c create mode 100644 drivers/staging/rtl8723au/os_dep/usb_intf.c create mode 100644 drivers/staging/rtl8723au/os_dep/usb_ops_linux.c create mode 100644 drivers/staging/rtl8723au/os_dep/xmit_linux.c (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c new file mode 100644 index 000000000000..1c99616f51ac --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -0,0 +1,4501 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _IOCTL_CFG80211_C_ + +#include +#include +#include +#include + +#include "ioctl_cfg80211.h" +#include + +#define RTW_MAX_MGMT_TX_CNT 8 + +#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 65535 /* ms */ +#define RTW_MAX_NUM_PMKIDS 4 + +#define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ + +static const u32 rtw_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +#define RATETAB_ENT(_rate, _rateid, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ +} + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_rate rtw_rates[] = { + RATETAB_ENT(10, 0x1, 0), + RATETAB_ENT(20, 0x2, 0), + RATETAB_ENT(55, 0x4, 0), + RATETAB_ENT(110, 0x8, 0), + RATETAB_ENT(60, 0x10, 0), + RATETAB_ENT(90, 0x20, 0), + RATETAB_ENT(120, 0x40, 0), + RATETAB_ENT(180, 0x80, 0), + RATETAB_ENT(240, 0x100, 0), + RATETAB_ENT(360, 0x200, 0), + RATETAB_ENT(480, 0x400, 0), + RATETAB_ENT(540, 0x800, 0), +}; + +#define rtw_a_rates (rtw_rates + 4) +#define RTW_A_RATES_NUM 8 +#define rtw_g_rates (rtw_rates + 0) +#define RTW_G_RATES_NUM 12 + +#define RTW_2G_CHANNELS_NUM 14 +#define RTW_5G_CHANNELS_NUM 37 + +static struct ieee80211_channel rtw_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), +}; + +static struct ieee80211_channel rtw_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 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(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static void rtw_2g_channels_init(struct ieee80211_channel *channels) +{ + memcpy((void *)channels, (void *)rtw_2ghz_channels, + sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM); +} + +static void rtw_5g_channels_init(struct ieee80211_channel *channels) +{ + memcpy((void *)channels, (void *)rtw_5ghz_a_channels, + sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM); +} + +static void rtw_2g_rates_init(struct ieee80211_rate *rates) +{ + memcpy(rates, rtw_g_rates, + sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM); +} + +static void rtw_5g_rates_init(struct ieee80211_rate *rates) +{ + memcpy(rates, rtw_a_rates, + sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM); +} + +static struct ieee80211_supported_band * +rtw_spt_band_alloc(enum ieee80211_band band) +{ + struct ieee80211_supported_band *spt_band = NULL; + int n_channels, n_bitrates; + + if (band == IEEE80211_BAND_2GHZ) { + n_channels = RTW_2G_CHANNELS_NUM; + n_bitrates = RTW_G_RATES_NUM; + } else if (band == IEEE80211_BAND_5GHZ) { + n_channels = RTW_5G_CHANNELS_NUM; + n_bitrates = RTW_A_RATES_NUM; + } else { + goto exit; + } + spt_band = kzalloc(sizeof(struct ieee80211_supported_band) + + sizeof(struct ieee80211_channel) * n_channels + + sizeof(struct ieee80211_rate) * n_bitrates, + GFP_KERNEL); + if (!spt_band) + goto exit; + + spt_band->channels = + (struct ieee80211_channel *)(((u8 *) spt_band) + + sizeof(struct + ieee80211_supported_band)); + spt_band->bitrates = + (struct ieee80211_rate *)(((u8 *) spt_band->channels) + + sizeof(struct ieee80211_channel) * + n_channels); + spt_band->band = band; + spt_band->n_channels = n_channels; + spt_band->n_bitrates = n_bitrates; + + if (band == IEEE80211_BAND_2GHZ) { + rtw_2g_channels_init(spt_band->channels); + rtw_2g_rates_init(spt_band->bitrates); + } else if (band == IEEE80211_BAND_5GHZ) { + rtw_5g_channels_init(spt_band->channels); + rtw_5g_rates_init(spt_band->bitrates); + } + + /* spt_band.ht_cap */ + +exit: + return spt_band; +} + +static const struct ieee80211_txrx_stypes +rtw_cfg80211_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_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_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_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) + }, +}; + +#define MAX_BSSINFO_LEN 1000 +static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter, + struct wlan_network *pnetwork) +{ + int ret = 0; + struct ieee80211_channel *notify_channel; + struct cfg80211_bss *bss; + /* struct ieee80211_supported_band *band; */ + u16 channel; + u32 freq; + u64 notify_timestamp; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; + size_t notify_ielen; + s32 notify_signal; + u8 buf[MAX_BSSINFO_LEN], *pbuf; + size_t len, bssinf_len = 0; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + u8 bc_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + struct wireless_dev *wdev = padapter->rtw_wdev; + struct wiphy *wiphy = wdev->wiphy; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + /* DBG_8723A("%s\n", __func__); */ + + bssinf_len = + pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr); + if (bssinf_len > MAX_BSSINFO_LEN) { + DBG_8723A("%s IE Length too long > %d byte\n", __func__, + MAX_BSSINFO_LEN); + goto exit; + } + + channel = pnetwork->network.Configuration.DSConfig; + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + notify_channel = ieee80211_get_channel(wiphy, freq); + + /* rtw_get_timestampe_from_ie23a() */ + notify_timestamp = jiffies_to_msecs(jiffies) * 1000; /* uSec */ + + notify_interval = + le16_to_cpu(*(u16 *) + rtw_get_beacon_interval23a_from_ie(pnetwork->network.IEs)); + notify_capability = + le16_to_cpu(*(u16 *) + rtw_get_capability23a_from_ie(pnetwork->network.IEs)); + + notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_; + notify_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; + + /* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM: + * signal strength in mBm (100*dBm) + */ + if (check_fwstate(pmlmepriv, _FW_LINKED) && + is_same_network23a(&pmlmepriv->cur_network.network, + &pnetwork->network)) { + notify_signal = 100 * translate_percentage_to_dbm(padapter->recvpriv.signal_strength); /* dbm */ + } else { + notify_signal = 100 * translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength); /* dbm */ + } + pbuf = buf; + + pwlanhdr = (struct ieee80211_hdr *)pbuf; + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + + SetSeqNum(pwlanhdr, 0); + + if (pnetwork->network.reserved == 1) { /* WIFI_BEACON */ + memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + SetFrameSubType(pbuf, WIFI_BEACON); + } else { + memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN); + SetFrameSubType(pbuf, WIFI_PROBERSP); + } + + memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN); + memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN); + + pbuf += sizeof(struct ieee80211_hdr_3addr); + len = sizeof(struct ieee80211_hdr_3addr); + + memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength); + len += pnetwork->network.IELength; + + bss = cfg80211_inform_bss_frame(wiphy, notify_channel, + (struct ieee80211_mgmt *)buf, len, + notify_signal, GFP_ATOMIC); + + if (unlikely(!bss)) { + DBG_8723A("rtw_cfg80211_inform_bss error\n"); + return -EINVAL; + } + + cfg80211_put_bss(wiphy, bss); + +exit: + return ret; +} + +void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct wireless_dev *pwdev = padapter->rtw_wdev; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + + DBG_8723A("%s(padapter =%p)\n", __func__, padapter); + + if (pwdev->iftype != NL80211_IFTYPE_STATION && + pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) + return; + +#ifdef CONFIG_8723AU_P2P + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", + __func__, rtw_p2p_role(pwdinfo), + rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); + } +#endif /* CONFIG_8723AU_P2P */ + + if (rtw_to_roaming(padapter) > 0) { + struct wiphy *wiphy = pwdev->wiphy; + struct ieee80211_channel *notify_channel; + u32 freq; + u16 channel = cur_network->network.Configuration.DSConfig; + + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = + ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = + ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + notify_channel = ieee80211_get_channel(wiphy, freq); + + DBG_8723A("%s call cfg80211_roamed\n", __func__); + cfg80211_roamed(padapter->pnetdev, notify_channel, + cur_network->network.MacAddress, + pmlmepriv->assoc_req + + sizeof(struct ieee80211_hdr_3addr) + 2, + pmlmepriv->assoc_req_len - + sizeof(struct ieee80211_hdr_3addr) - 2, + pmlmepriv->assoc_rsp + + sizeof(struct ieee80211_hdr_3addr) + 6, + pmlmepriv->assoc_rsp_len - + sizeof(struct ieee80211_hdr_3addr) - 6, + GFP_ATOMIC); + } else { + cfg80211_connect_result(padapter->pnetdev, + cur_network->network.MacAddress, + pmlmepriv->assoc_req + + sizeof(struct ieee80211_hdr_3addr) + 2, + pmlmepriv->assoc_req_len - + sizeof(struct ieee80211_hdr_3addr) - 2, + pmlmepriv->assoc_rsp + + sizeof(struct ieee80211_hdr_3addr) + 6, + pmlmepriv->assoc_rsp_len - + sizeof(struct ieee80211_hdr_3addr) - 6, + WLAN_STATUS_SUCCESS, GFP_ATOMIC); + } +} + +void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wireless_dev *pwdev = padapter->rtw_wdev; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + + DBG_8723A("%s(padapter =%p)\n", __func__, padapter); + + if (pwdev->iftype != NL80211_IFTYPE_STATION && + pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) + return; + +#ifdef CONFIG_8723AU_P2P + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + del_timer_sync(&pwdinfo->find_phase_timer); + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + del_timer_sync(&pwdinfo->pre_tx_scan_timer); + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + + DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n", + __func__, rtw_p2p_role(pwdinfo), + rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo)); + } +#endif /* CONFIG_8723AU_P2P */ + + if (!padapter->mlmepriv.not_indic_disco) { + if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) { + cfg80211_connect_result(padapter->pnetdev, NULL, NULL, + 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_ATOMIC); + } else { + cfg80211_disconnected(padapter->pnetdev, 0, NULL, + 0, GFP_ATOMIC); + } + } +} + +#ifdef CONFIG_8723AU_AP_MODE +static u8 set_pairwise_key(struct rtw_adapter *padapter, struct sta_info *psta) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL); + if (psetstakey_para == NULL) { + kfree(ph2c); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + + psetstakey_para->algorithm = (u8) psta->dot118021XPrivacy; + + memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); + + memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); + + res = rtw_enqueue_cmd23a(pcmdpriv, ph2c); + +exit: + return res; +} + +static int set_group_key(struct rtw_adapter *padapter, u8 *key, u8 alg, + int keyid) +{ + u8 keylen; + struct cmd_obj *pcmd; + struct setkey_parm *psetkeyparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + int res = _SUCCESS; + + DBG_8723A("%s\n", __func__); + + pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); + if (!pcmd) { + res = _FAIL; + goto exit; + } + psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); + if (!psetkeyparm) { + kfree(pcmd); + res = _FAIL; + goto exit; + } + + psetkeyparm->keyid = (u8) keyid; + if (is_wep_enc(alg)) + padapter->mlmepriv.key_mask |= CHKBIT(psetkeyparm->keyid); + + psetkeyparm->algorithm = alg; + + psetkeyparm->set_tx = 1; + + switch (alg) { + case _WEP40_: + keylen = 5; + break; + case _WEP104_: + keylen = 13; + break; + case _TKIP_: + case _TKIP_WTMIC_: + case _AES_: + default: + keylen = 16; + } + + memcpy(&psetkeyparm->key[0], key, keylen); + + pcmd->cmdcode = _SetKey_CMD_; + pcmd->parmbuf = (u8 *) psetkeyparm; + pcmd->cmdsz = (sizeof(struct setkey_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + INIT_LIST_HEAD(&pcmd->list); + + res = rtw_enqueue_cmd23a(pcmdpriv, pcmd); + +exit: + return res; +} + +static int set_wep_key(struct rtw_adapter *padapter, u8 *key, u8 keylen, + int keyid) +{ + u8 alg; + + switch (keylen) { + case 5: + alg = _WEP40_; + break; + case 13: + alg = _WEP104_; + break; + default: + alg = _NO_PRIVACY_; + } + + return set_group_key(padapter, key, alg, keyid); +} + +static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, + struct ieee_param *param, + u32 param_len) +{ + int ret = 0; + u32 wep_key_idx, wep_key_len; + struct sta_info *psta = NULL, *pbcmc_sta = NULL; + struct rtw_adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sta_priv *pstapriv = &padapter->stapriv; + + DBG_8723A("%s\n", __func__); + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + /* sizeof(struct ieee_param) = 64 bytes; */ + /* if (param_len != (u32) ((u8 *) param->u.crypt.key - + (u8 *) param) + param->u.crypt.key_len) */ + if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) { + ret = -EINVAL; + goto exit; + } + + if (is_broadcast_ether_addr(param->sta_addr)) { + if (param->u.crypt.idx >= WEP_KEYS) { + ret = -EINVAL; + goto exit; + } + } else { + psta = rtw_get_stainfo23a(pstapriv, param->sta_addr); + if (!psta) { + /* ret = -EINVAL; */ + DBG_8723A("rtw_set_encryption(), sta has already " + "been removed or never been added\n"); + goto exit; + } + } + + if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) { + /* todo:clear default encryption keys */ + + DBG_8723A("clear default encryption keys, keyid =%d\n", + param->u.crypt.idx); + + goto exit; + } + + if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) { + DBG_8723A("r871x_set_encryption, crypt.alg = WEP\n"); + + wep_key_idx = param->u.crypt.idx; + wep_key_len = param->u.crypt.key_len; + + DBG_8723A("r871x_set_encryption, wep_key_idx =%d, len =%d\n", + wep_key_idx, wep_key_len); + + if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { + ret = -EINVAL; + goto exit; + } + + if (wep_key_len > 0) { + wep_key_len = wep_key_len <= 5 ? 5 : 13; + } + + if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { + /* wep default key has not been set, so use + this key index as default key. */ + + psecuritypriv->ndisencryptstatus = + Ndis802_11Encryption1Enabled; + psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; + psecuritypriv->dot118021XGrpPrivacy = _WEP40_; + + if (wep_key_len == 13) { + psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; + psecuritypriv->dot118021XGrpPrivacy = _WEP104_; + } + + psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; + } + + memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], + param->u.crypt.key, wep_key_len); + + psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; + + set_wep_key(padapter, param->u.crypt.key, wep_key_len, + wep_key_idx); + + goto exit; + + } + + if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */ + if (param->u.crypt.set_tx == 0) { /* group key */ + if (strcmp(param->u.crypt.alg, "WEP") == 0) { + DBG_8723A("%s, set group_key, WEP\n", + __func__); + + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt.idx]. + skey, param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt.key_len)); + + psecuritypriv->dot118021XGrpPrivacy = _WEP40_; + if (param->u.crypt.key_len == 13) { + psecuritypriv->dot118021XGrpPrivacy = + _WEP104_; + } + + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { + DBG_8723A("%s, set group_key, TKIP\n", + __func__); + + psecuritypriv->dot118021XGrpPrivacy = _TKIP_; + + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt.idx]. + skey, param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt.key_len)); + + /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ + /* set mic key */ + memcpy(psecuritypriv-> + dot118021XGrptxmickey[param->u.crypt. + idx].skey, + ¶m->u.crypt.key[16], 8); + memcpy(psecuritypriv-> + dot118021XGrprxmickey[param->u.crypt. + idx].skey, + ¶m->u.crypt.key[24], 8); + + psecuritypriv->busetkipkey = true; + + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { + DBG_8723A("%s, set group_key, CCMP\n", + __func__); + + psecuritypriv->dot118021XGrpPrivacy = _AES_; + + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt.idx]. + skey, param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt.key_len)); + } else { + DBG_8723A("%s, set group_key, none\n", + __func__); + + psecuritypriv->dot118021XGrpPrivacy = + _NO_PRIVACY_; + } + + psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; + + psecuritypriv->binstallGrpkey = true; + + psecuritypriv->dot11PrivacyAlgrthm = + psecuritypriv->dot118021XGrpPrivacy; + + set_group_key(padapter, param->u.crypt.key, + psecuritypriv->dot118021XGrpPrivacy, + param->u.crypt.idx); + + pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); + if (pbcmc_sta) { + pbcmc_sta->ieee8021x_blocked = false; + /* rx will use bmc_sta's dot118021XPrivacy */ + pbcmc_sta->dot118021XPrivacy = + psecuritypriv->dot118021XGrpPrivacy; + + } + + } + + goto exit; + } + + if (psecuritypriv->dot11AuthAlgrthm == + dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */ + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + if (param->u.crypt.set_tx == 1) { + /* pairwise key */ + memcpy(psta->dot118021x_UncstKey.skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt.key_len)); + + if (!strcmp(param->u.crypt.alg, "WEP")) { + DBG_8723A("%s, set pairwise key, WEP\n", + __func__); + + psta->dot118021XPrivacy = _WEP40_; + if (param->u.crypt.key_len == 13) { + psta->dot118021XPrivacy = + _WEP104_; + } + } else if (!strcmp(param->u.crypt.alg, "TKIP")) { + DBG_8723A("%s, set pairwise key, " + "TKIP\n", __func__); + + psta->dot118021XPrivacy = _TKIP_; + + /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ + /* set mic key */ + memcpy(psta->dot11tkiptxmickey.skey, + ¶m->u.crypt.key[16], 8); + memcpy(psta->dot11tkiprxmickey.skey, + ¶m->u.crypt.key[24], 8); + + psecuritypriv->busetkipkey = true; + + } else if (!strcmp(param->u.crypt.alg, "CCMP")) { + + DBG_8723A("%s, set pairwise key, " + "CCMP\n", __func__); + + psta->dot118021XPrivacy = _AES_; + } else { + DBG_8723A("%s, set pairwise key, " + "none\n", __func__); + + psta->dot118021XPrivacy = _NO_PRIVACY_; + } + + set_pairwise_key(padapter, psta); + + psta->ieee8021x_blocked = false; + + psta->bpairwise_key_installed = true; + } else { /* group key??? */ + if (!strcmp(param->u.crypt.alg, "WEP")) { + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt. + idx].skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt. + key_len)); + + psecuritypriv->dot118021XGrpPrivacy = + _WEP40_; + if (param->u.crypt.key_len == 13) { + psecuritypriv-> + dot118021XGrpPrivacy = + _WEP104_; + } + } else if (!strcmp(param->u.crypt.alg, "TKIP")) { + psecuritypriv->dot118021XGrpPrivacy = + _TKIP_; + + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt. + idx].skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt. + key_len)); + + /* DEBUG_ERR("set key length :param->u" + ".crypt.key_len =%d\n", + param->u.crypt.key_len); */ + /* set mic key */ + memcpy(psecuritypriv-> + dot118021XGrptxmickey[param->u. + crypt.idx]. + skey, ¶m->u.crypt.key[16], + 8); + memcpy(psecuritypriv-> + dot118021XGrprxmickey[param->u. + crypt.idx]. + skey, ¶m->u.crypt.key[24], + 8); + + psecuritypriv->busetkipkey = true; + + } else if (!strcmp(param->u.crypt.alg, "CCMP")) { + psecuritypriv->dot118021XGrpPrivacy = + _AES_; + + memcpy(psecuritypriv-> + dot118021XGrpKey[param->u.crypt. + idx].skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt. + key_len)); + } else { + psecuritypriv->dot118021XGrpPrivacy = + _NO_PRIVACY_; + } + + psecuritypriv->dot118021XGrpKeyid = + param->u.crypt.idx; + + psecuritypriv->binstallGrpkey = true; + + psecuritypriv->dot11PrivacyAlgrthm = + psecuritypriv->dot118021XGrpPrivacy; + + set_group_key(padapter, param->u.crypt.key, + psecuritypriv-> + dot118021XGrpPrivacy, + param->u.crypt.idx); + + pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); + if (pbcmc_sta) { + /* rx will use bmc_sta's + dot118021XPrivacy */ + pbcmc_sta->ieee8021x_blocked = false; + pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; + } + } + } + } + +exit: + + return ret; + +} +#endif + +static int rtw_cfg80211_set_encryption(struct net_device *dev, + struct ieee_param *param, u32 param_len) +{ + int ret = 0; + u32 wep_key_idx, wep_key_len; + struct rtw_adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + + + + DBG_8723A("%s\n", __func__); + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len < + (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + + param->u.crypt.key_len) { + ret = -EINVAL; + goto exit; + } + + if (is_broadcast_ether_addr(param->sta_addr)) { + if (param->u.crypt.idx >= WEP_KEYS) { + ret = -EINVAL; + goto exit; + } + } else { + ret = -EINVAL; + goto exit; + } + + if (strcmp(param->u.crypt.alg, "WEP") == 0) { + RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, + ("wpa_set_encryption, crypt.alg = WEP\n")); + DBG_8723A("wpa_set_encryption, crypt.alg = WEP\n"); + + wep_key_idx = param->u.crypt.idx; + wep_key_len = param->u.crypt.key_len; + + if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) { + ret = -EINVAL; + goto exit; + } + + if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { + /* wep default key has not been set, so use this + key index as default key. */ + + wep_key_len = wep_key_len <= 5 ? 5 : 13; + + psecuritypriv->ndisencryptstatus = + Ndis802_11Encryption1Enabled; + psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; + psecuritypriv->dot118021XGrpPrivacy = _WEP40_; + + if (wep_key_len == 13) { + psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; + psecuritypriv->dot118021XGrpPrivacy = _WEP104_; + } + + psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; + } + + memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], + param->u.crypt.key, wep_key_len); + + psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len; + + rtw_set_key23a(padapter, psecuritypriv, wep_key_idx, 0); + + goto exit; + } + + if (padapter->securitypriv.dot11AuthAlgrthm == + dot11AuthAlgrthm_8021X) { /* 802_1x */ + struct sta_info *psta, *pbcmc_sta; + struct sta_priv *pstapriv = &padapter->stapriv; + + if (check_fwstate(pmlmepriv, + WIFI_STATION_STATE | WIFI_MP_STATE)) { + /* sta mode */ + psta = rtw_get_stainfo23a(pstapriv, get_bssid(pmlmepriv)); + if (psta == NULL) { + DBG_8723A("%s, : Obtain Sta_info fail\n", + __func__); + } else { + /* Jeff: don't disable ieee8021x_blocked + while clearing key */ + if (strcmp(param->u.crypt.alg, "none") != 0) + psta->ieee8021x_blocked = false; + + if ((padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption2Enabled) || + (padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption3Enabled)) { + psta->dot118021XPrivacy = + padapter->securitypriv. + dot11PrivacyAlgrthm; + } + + if (param->u.crypt.set_tx == 1) { + /* pairwise key */ + DBG_8723A("%s, : param->u.crypt.set_tx" + " == 1\n", __func__); + + memcpy(psta->dot118021x_UncstKey.skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt. + key_len)); + + if (strcmp(param->u.crypt.alg, + "TKIP") == 0) { + memcpy(psta->dot11tkiptxmickey. + skey, + ¶m->u.crypt.key[16], + 8); + memcpy(psta->dot11tkiprxmickey. + skey, + ¶m->u.crypt.key[24], + 8); + + padapter->securitypriv. + busetkipkey = false; + } + DBG_8723A(" ~~~~set sta key:unicastkey\n"); + + rtw_setstakey_cmd23a(padapter, + (unsigned char *)psta, + true); + } else { /* group key */ + memcpy(padapter->securitypriv. + dot118021XGrpKey[param->u.crypt. + idx].skey, + param->u.crypt.key, + (param->u.crypt.key_len > + 16 ? 16 : param->u.crypt. + key_len)); + memcpy(padapter->securitypriv. + dot118021XGrptxmickey[param->u. + crypt.idx]. + skey, ¶m->u.crypt.key[16], + 8); + memcpy(padapter->securitypriv. + dot118021XGrprxmickey[param->u. + crypt.idx]. + skey, ¶m->u.crypt.key[24], + 8); + padapter->securitypriv.binstallGrpkey = + true; + /* DEBUG_ERR((" param->u.crypt.key_len" + "=%d\n", param->u.crypt.key_len)); */ + DBG_8723A + (" ~~~~set sta key:groupkey\n"); + + padapter->securitypriv. + dot118021XGrpKeyid = + param->u.crypt.idx; + + rtw_set_key23a(padapter, + &padapter->securitypriv, + param->u.crypt.idx, 1); +#ifdef CONFIG_8723AU_P2P + if (rtw_p2p_chk_state + (pwdinfo, + P2P_STATE_PROVISIONING_ING)) { + rtw_p2p_set_state(pwdinfo, + P2P_STATE_PROVISIONING_DONE); + } +#endif /* CONFIG_8723AU_P2P */ + + } + } + + pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter); + if (pbcmc_sta) { + /* Jeff: don't disable ieee8021x_blocked + while clearing key */ + if (strcmp(param->u.crypt.alg, "none") != 0) + pbcmc_sta->ieee8021x_blocked = false; + + if ((padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption2Enabled) || + (padapter->securitypriv.ndisencryptstatus == + Ndis802_11Encryption3Enabled)) { + pbcmc_sta->dot118021XPrivacy = + padapter->securitypriv. + dot11PrivacyAlgrthm; + } + } + } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { /* adhoc mode */ + } + } + +exit: + + DBG_8723A("%s, ret =%d\n", __func__, ret); + + + + return ret; +} + +static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params) +{ + char *alg_name; + u32 param_len; + struct ieee_param *param = NULL; + int ret = 0; + struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + DBG_8723A(FUNC_NDEV_FMT " adding key for %pM\n", FUNC_NDEV_ARG(ndev), + mac_addr); + DBG_8723A("cipher = 0x%x\n", params->cipher); + DBG_8723A("key_len = 0x%x\n", params->key_len); + DBG_8723A("seq_len = 0x%x\n", params->seq_len); + DBG_8723A("key_index =%d\n", key_index); + DBG_8723A("pairwise =%d\n", pairwise); + + param_len = sizeof(struct ieee_param) + params->key_len; + param = kzalloc(param_len, GFP_KERNEL); + if (param == NULL) + return -1; + + param->cmd = IEEE_CMD_SET_ENCRYPTION; + memset(param->sta_addr, 0xff, ETH_ALEN); + + switch (params->cipher) { + case IW_AUTH_CIPHER_NONE: + /* todo: remove key */ + /* remove = 1; */ + alg_name = "none"; + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + alg_name = "WEP"; + break; + case WLAN_CIPHER_SUITE_TKIP: + alg_name = "TKIP"; + break; + case WLAN_CIPHER_SUITE_CCMP: + alg_name = "CCMP"; + break; + + default: + ret = -ENOTSUPP; + goto addkey_end; + } + + strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); + + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */ + } else { + param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */ + } + + /* param->u.crypt.idx = key_index - 1; */ + param->u.crypt.idx = key_index; + + if (params->seq_len && params->seq) { + memcpy(param->u.crypt.seq, params->seq, params->seq_len); + } + + if (params->key_len && params->key) { + param->u.crypt.key_len = params->key_len; + memcpy(param->u.crypt.key, params->key, params->key_len); + } + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + ret = rtw_cfg80211_set_encryption(ndev, param, param_len); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { +#ifdef CONFIG_8723AU_AP_MODE + if (mac_addr) + memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN); + + ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len); +#endif + } else { + DBG_8723A("error! fw_state = 0x%x, iftype =%d\n", + pmlmepriv->fw_state, rtw_wdev->iftype); + + } + +addkey_end: + kfree(param); + + return ret; +} + +static int +cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, + void (*callback) (void *cookie, struct key_params *)) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} + +static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + struct rtw_adapter *padapter = netdev_priv(ndev); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + DBG_8723A(FUNC_NDEV_FMT " key_index =%d\n", FUNC_NDEV_ARG(ndev), + key_index); + + if (key_index == psecuritypriv->dot11PrivacyKeyIndex) { + /* clear the flag of wep default key set. */ + psecuritypriv->bWepDefaultKeyIdxSet = 0; + } + + return 0; +} + +static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, + bool unicast, bool multicast) +{ + struct rtw_adapter *padapter = netdev_priv(ndev); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + DBG_8723A(FUNC_NDEV_FMT " key_index =%d" + ", unicast =%d, multicast =%d.\n", FUNC_NDEV_ARG(ndev), + key_index, unicast, multicast); + + if ((key_index < WEP_KEYS) && + ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || + (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) { + /* set wep default key */ + psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; + + psecuritypriv->dot11PrivacyKeyIndex = key_index; + + psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; + psecuritypriv->dot118021XGrpPrivacy = _WEP40_; + if (psecuritypriv->dot11DefKeylen[key_index] == 13) { + psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; + psecuritypriv->dot118021XGrpPrivacy = _WEP104_; + } + + /* set the flag to represent that wep default key + has been set */ + psecuritypriv->bWepDefaultKeyIdxSet = 1; + } + + return 0; +} + +static int cfg80211_rtw_get_station(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + int ret = 0; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + + sinfo->filled = 0; + + if (!mac) { + DBG_8723A(FUNC_NDEV_FMT " mac ==%p\n", FUNC_NDEV_ARG(ndev), mac); + ret = -ENOENT; + goto exit; + } + + psta = rtw_get_stainfo23a(pstapriv, mac); + if (psta == NULL) { + DBG_8723A("%s, sta_info is null\n", __func__); + ret = -ENOENT; + goto exit; + } +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A(FUNC_NDEV_FMT " mac =" MAC_FMT "\n", FUNC_NDEV_ARG(ndev), + MAC_ARG(mac)); +#endif + + /* for infra./P2PClient mode */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && + check_fwstate(pmlmepriv, _FW_LINKED)) { + struct wlan_network *cur_network = &pmlmepriv->cur_network; + + if (memcmp(mac, cur_network->network.MacAddress, ETH_ALEN)) { + DBG_8723A("%s, mismatch bssid =" MAC_FMT "\n", __func__, + MAC_ARG(cur_network->network.MacAddress)); + ret = -ENOENT; + goto exit; + } + + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv. + signal_strength); + + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rtw_get_cur_max_rate23a(padapter); + + sinfo->filled |= STATION_INFO_RX_PACKETS; + sinfo->rx_packets = sta_rx_data_pkts(psta); + + sinfo->filled |= STATION_INFO_TX_PACKETS; + sinfo->tx_packets = psta->sta_stats.tx_pkts; + } + + /* for Ad-Hoc/AP mode */ + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || + check_fwstate(pmlmepriv, WIFI_AP_STATE)) && + check_fwstate(pmlmepriv, _FW_LINKED) + ) { + /* TODO: should acquire station info... */ + } + +exit: + return ret; +} + +static int cfg80211_rtw_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + enum nl80211_iftype old_type; + enum ndis_802_11_net_infra networkType; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy); +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + int ret = 0; + u8 change = false; + + DBG_8723A(FUNC_NDEV_FMT " call netdev_open23a\n", FUNC_NDEV_ARG(ndev)); + if (netdev_open23a(ndev) != 0) { + ret = -EPERM; + goto exit; + } + + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = -EPERM; + goto exit; + } + + old_type = rtw_wdev->iftype; + DBG_8723A(FUNC_NDEV_FMT " old_iftype =%d, new_iftype =%d\n", + FUNC_NDEV_ARG(ndev), old_type, type); + + if (old_type != type) { + change = true; + pmlmeext->action_public_rxseq = 0xffff; + pmlmeext->action_public_dialog_token = 0xff; + } + + switch (type) { + case NL80211_IFTYPE_ADHOC: + networkType = Ndis802_11IBSS; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + networkType = Ndis802_11Infrastructure; +#ifdef CONFIG_8723AU_P2P + if (change && rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + del_timer_sync(&pwdinfo->find_phase_timer); + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + del_timer_sync(&pwdinfo->pre_tx_scan_timer); + + /* it means remove GO and change mode from AP(GO) + to station(P2P DEVICE) */ + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + + DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =" + "%d\n", __func__, rtw_p2p_role(pwdinfo), + rtw_p2p_state(pwdinfo), + rtw_p2p_pre_state(pwdinfo)); + } +#endif /* CONFIG_8723AU_P2P */ + break; + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + networkType = Ndis802_11APMode; +#ifdef CONFIG_8723AU_P2P + if (change && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + /* it means P2P Group created, we will be GO + and change mode from P2P DEVICE to AP(GO) */ + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } +#endif /* CONFIG_8723AU_P2P */ + break; + default: + return -EOPNOTSUPP; + } + + rtw_wdev->iftype = type; + + if (rtw_set_802_11_infrastructure_mode23a(padapter, networkType) == false) { + rtw_wdev->iftype = old_type; + ret = -EPERM; + goto exit; + } + + rtw_setopmode_cmd23a(padapter, networkType); + +exit: + return ret; +} + +void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, + bool aborted) +{ + spin_lock_bh(&pwdev_priv->scan_req_lock); + if (pwdev_priv->scan_request != NULL) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s with scan req\n", __func__); +#endif + if (pwdev_priv->scan_request->wiphy != + pwdev_priv->rtw_wdev->wiphy) + DBG_8723A("error wiphy compare\n"); + else + cfg80211_scan_done(pwdev_priv->scan_request, aborted); + + pwdev_priv->scan_request = NULL; + } else { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s without scan req\n", __func__); +#endif + } + spin_unlock_bh(&pwdev_priv->scan_req_lock); +} + +void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter) +{ + struct list_head *plist, *phead, *ptmp; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + struct wlan_network *pnetwork; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s\n", __func__); +#endif + + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + + phead = get_list_head(queue); + + list_for_each_safe(plist, ptmp, phead) { + pnetwork = container_of(plist, struct wlan_network, list); + + /* report network only if the current channel set + contains the channel to which this network belongs */ + if (rtw_ch_set_search_ch23a + (padapter->mlmeextpriv.channel_set, + pnetwork->network.Configuration.DSConfig) >= 0) + rtw_cfg80211_inform_bss(padapter, pnetwork); + } + + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); + + /* call this after other things have been done */ + rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), + false); +} + +static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter, + char *buf, int len) +{ + int ret = 0; + uint wps_ielen = 0; + u8 *wps_ie; + u32 p2p_ielen = 0; + u8 *p2p_ie; + u32 wfd_ielen = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, ielen =%d\n", __func__, len); +#endif + + if (len > 0) { + wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); + if (wps_ie) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("probe_req_wps_ielen =%d\n", wps_ielen); +#endif + if (pmlmepriv->wps_probe_req_ie) { + pmlmepriv->wps_probe_req_ie_len = 0; + kfree(pmlmepriv->wps_probe_req_ie); + pmlmepriv->wps_probe_req_ie = NULL; + } + + pmlmepriv->wps_probe_req_ie = + kmalloc(wps_ielen, GFP_KERNEL); + if (pmlmepriv->wps_probe_req_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + } + memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen); + pmlmepriv->wps_probe_req_ie_len = wps_ielen; + } +#ifdef CONFIG_8723AU_P2P + p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); + if (p2p_ie) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("probe_req_p2p_ielen =%d\n", p2p_ielen); +#endif + + if (pmlmepriv->p2p_probe_req_ie) { + pmlmepriv->p2p_probe_req_ie_len = 0; + kfree(pmlmepriv->p2p_probe_req_ie); + pmlmepriv->p2p_probe_req_ie = NULL; + } + + pmlmepriv->p2p_probe_req_ie = + kmalloc(p2p_ielen, GFP_KERNEL); + if (pmlmepriv->p2p_probe_req_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen); + pmlmepriv->p2p_probe_req_ie_len = p2p_ielen; + } +#endif /* CONFIG_8723AU_P2P */ + + /* buf += p2p_ielen; */ + /* len -= p2p_ielen; */ + +#ifdef CONFIG_8723AU_P2P + if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("probe_req_wfd_ielen =%d\n", wfd_ielen); +#endif + + if (pmlmepriv->wfd_probe_req_ie) { + pmlmepriv->wfd_probe_req_ie_len = 0; + kfree(pmlmepriv->wfd_probe_req_ie); + pmlmepriv->wfd_probe_req_ie = NULL; + } + + pmlmepriv->wfd_probe_req_ie = + kmalloc(wfd_ielen, GFP_KERNEL); + if (pmlmepriv->wfd_probe_req_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_req_ie, + &pmlmepriv->wfd_probe_req_ie_len); + } +#endif /* CONFIG_8723AU_P2P */ + + } + + return ret; +} + +static int cfg80211_rtw_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + int i; + u8 _status = false; + int ret = 0; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT]; + struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_8723AU_P2P */ + struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); + struct cfg80211_ssid *ssids = request->ssids; + int social_channel = 0; + bool need_indicate_scan_done = false; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); +#endif + + spin_lock_bh(&pwdev_priv->scan_req_lock); + pwdev_priv->scan_request = request; + spin_unlock_bh(&pwdev_priv->scan_req_lock); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s under WIFI_AP_STATE\n", __func__); +#endif + /* need_indicate_scan_done = true; */ + /* goto check_need_indicate_scan_done; */ + } + + if (rtw_pwr_wakeup(padapter) == _FAIL) { + need_indicate_scan_done = true; + goto check_need_indicate_scan_done; + } +#ifdef CONFIG_8723AU_P2P + if (ssids->ssid != NULL && + !memcmp(ssids->ssid, "DIRECT-", 7) && + rtw_get_p2p_ie23a((u8 *) request->ie, request->ie_len, NULL, NULL)) { + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); + wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; + } else { + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, + rtw_p2p_role(pwdinfo), + rtw_p2p_state(pwdinfo)); +#endif + } + rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); + + if (request->n_channels == 3 && + request->channels[0]->hw_value == 1 && + request->channels[1]->hw_value == 6 && + request->channels[2]->hw_value == 11) + social_channel = 1; + } +#endif /* CONFIG_8723AU_P2P */ + + if (request->ie && request->ie_len > 0) { + rtw_cfg80211_set_probe_req_wpsp2pie(padapter, + (u8 *) request->ie, + request->ie_len); + } + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { + DBG_8723A("%s, bBusyTraffic == true\n", __func__); + need_indicate_scan_done = true; + goto check_need_indicate_scan_done; + } + if (rtw_is_scan_deny(padapter)) { + DBG_8723A(FUNC_ADPT_FMT ": scan deny\n", + FUNC_ADPT_ARG(padapter)); + need_indicate_scan_done = true; + goto check_need_indicate_scan_done; + } + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == + true) { + DBG_8723A("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state); + need_indicate_scan_done = true; + goto check_need_indicate_scan_done; + } +#ifdef CONFIG_8723AU_P2P + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { + rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); + rtw_free_network_queue23a(padapter, true); + + if (social_channel == 0) + rtw_p2p_findphase_ex_set(pwdinfo, + P2P_FINDPHASE_EX_NONE); + else + rtw_p2p_findphase_ex_set(pwdinfo, + P2P_FINDPHASE_EX_SOCIAL_LAST); + } +#endif /* CONFIG_8723AU_P2P */ + + memset(ssid, 0, sizeof(struct cfg80211_ssid) * RTW_SSID_SCAN_AMOUNT); + /* parsing request ssids, n_ssids */ + for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("ssid =%s, len =%d\n", ssids[i].ssid, + ssids[i].ssid_len); +#endif + memcpy(ssid[i].ssid, ssids[i].ssid, ssids[i].ssid_len); + ssid[i].ssid_len = ssids[i].ssid_len; + } + + /* parsing channels, n_channels */ + memset(ch, 0, + sizeof(struct rtw_ieee80211_channel) * RTW_CHANNEL_SCAN_AMOUNT); + + if (request->n_channels == 1) { + for (i = 0; i < request->n_channels && + i < RTW_CHANNEL_SCAN_AMOUNT; i++) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A(FUNC_ADPT_FMT CHAN_FMT "\n", + FUNC_ADPT_ARG(padapter), + CHAN_ARG(request->channels[i])); +#endif + ch[i].hw_value = request->channels[i]->hw_value; + ch[i].flags = request->channels[i]->flags; + } + } + + spin_lock_bh(&pmlmepriv->lock); + if (request->n_channels == 1) { + memcpy(&ch[1], &ch[0], sizeof(struct rtw_ieee80211_channel)); + memcpy(&ch[2], &ch[0], sizeof(struct rtw_ieee80211_channel)); + _status = rtw_sitesurvey_cmd23a(padapter, ssid, + RTW_SSID_SCAN_AMOUNT, ch, 3); + } else { + _status = rtw_sitesurvey_cmd23a(padapter, ssid, + RTW_SSID_SCAN_AMOUNT, NULL, 0); + } + spin_unlock_bh(&pmlmepriv->lock); + + if (_status == false) + ret = -1; + +check_need_indicate_scan_done: + if (need_indicate_scan_done) + rtw_cfg80211_surveydone_event_callback(padapter); + return ret; +} + +static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + DBG_8723A("%s\n", __func__); + return 0; +} + +static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ibss_params *params) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} + +static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} + +static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, + u32 wpa_version) +{ + DBG_8723A("%s, wpa_version =%d\n", __func__, wpa_version); + + if (!wpa_version) { + psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; + return 0; + } + + if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) { + psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK; + } + +/* + if (wpa_version & NL80211_WPA_VERSION_2) + { + psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; + } +*/ + + return 0; +} + +static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv, + enum nl80211_auth_type sme_auth_type) +{ + DBG_8723A("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type); + + switch (sme_auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; + + break; + case NL80211_AUTHTYPE_OPEN_SYSTEM: + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; + + if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA) + psecuritypriv->dot11AuthAlgrthm = + dot11AuthAlgrthm_8021X; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; + + psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; + default: + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; + /* return -ENOTSUPP; */ + } + + return 0; +} + +static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, + u32 cipher, bool ucast) +{ + u32 ndisencryptstatus = Ndis802_11EncryptionDisabled; + + u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm : + &psecuritypriv->dot118021XGrpPrivacy; + + DBG_8723A("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher); + + if (!cipher) { + *profile_cipher = _NO_PRIVACY_; + psecuritypriv->ndisencryptstatus = ndisencryptstatus; + return 0; + } + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = _NO_PRIVACY_; + ndisencryptstatus = Ndis802_11EncryptionDisabled; + break; + case WLAN_CIPHER_SUITE_WEP40: + *profile_cipher = _WEP40_; + ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; + case WLAN_CIPHER_SUITE_WEP104: + *profile_cipher = _WEP104_; + ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; + case WLAN_CIPHER_SUITE_TKIP: + *profile_cipher = _TKIP_; + ndisencryptstatus = Ndis802_11Encryption2Enabled; + break; + case WLAN_CIPHER_SUITE_CCMP: + *profile_cipher = _AES_; + ndisencryptstatus = Ndis802_11Encryption3Enabled; + break; + default: + DBG_8723A("Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + if (ucast) + psecuritypriv->ndisencryptstatus = ndisencryptstatus; + + return 0; +} + +static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, + u32 key_mgt) +{ + DBG_8723A("%s, key_mgt = 0x%x\n", __func__, key_mgt); + + if (key_mgt == WLAN_AKM_SUITE_8021X) + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + else if (key_mgt == WLAN_AKM_SUITE_PSK) + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + else + DBG_8723A("Invalid key mgt: 0x%x\n", key_mgt); + + return 0; +} + +static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie, + size_t ielen) +{ + u8 *buf = NULL, *pos = NULL; + int group_cipher = 0, pairwise_cipher = 0; + int ret = 0; + int wpa_ielen = 0; + int wpa2_ielen = 0; + u8 *pwpa, *pwpa2; + u8 null_addr[] = { 0, 0, 0, 0, 0, 0 }; + int i; + + if (!pie || !ielen) { + /* Treat this as normal case, but need to clear + WIFI_UNDER_WPS */ + _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); + goto exit; + } + if (ielen > MAX_WPA_IE_LEN + MAX_WPS_IE_LEN + MAX_P2P_IE_LEN) { + ret = -EINVAL; + goto exit; + } + buf = kzalloc(ielen, GFP_KERNEL); + if (buf == NULL) { + ret = -ENOMEM; + goto exit; + } + memcpy(buf, pie, ielen); + + /* dump */ + DBG_8723A("set wpa_ie(length:%zu):\n", ielen); + for (i = 0; i < ielen; i = i + 8) + DBG_8723A("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", + buf[i], buf[i + 1], + buf[i + 2], buf[i + 3], buf[i + 4], + buf[i + 5], buf[i + 6], buf[i + 7]); + pos = buf; + if (ielen < RSN_HEADER_LEN) { + RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, + ("Ie len too short %d\n", (int)ielen)); + ret = -1; + goto exit; + } + + pwpa = rtw_get_wpa_ie23a(buf, &wpa_ielen, ielen); + if (pwpa && wpa_ielen > 0) { + if (rtw_parse_wpa_ie23a(pwpa, wpa_ielen + 2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { + padapter->securitypriv.dot11AuthAlgrthm = + dot11AuthAlgrthm_8021X; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPAPSK; + memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], + wpa_ielen + 2); + + DBG_8723A("got wpa_ie, wpa_ielen:%u\n", wpa_ielen); + } + } + + pwpa2 = rtw_get_wpa2_ie23a(buf, &wpa2_ielen, ielen); + if (pwpa2 && wpa2_ielen > 0) { + if (rtw_parse_wpa2_ie23a (pwpa2, wpa2_ielen + 2, &group_cipher, + &pairwise_cipher, NULL) == _SUCCESS) { + padapter->securitypriv.dot11AuthAlgrthm = + dot11AuthAlgrthm_8021X; + padapter->securitypriv.ndisauthtype = + Ndis802_11AuthModeWPA2PSK; + memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], + wpa2_ielen + 2); + + DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen); + } + } + + if (group_cipher == 0) { + group_cipher = WPA_CIPHER_NONE; + } + if (pairwise_cipher == 0) { + pairwise_cipher = WPA_CIPHER_NONE; + } + + switch (group_cipher) { + case WPA_CIPHER_NONE: + padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.dot118021XGrpPrivacy = _AES_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + } + + switch (pairwise_cipher) { + case WPA_CIPHER_NONE: + padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; + padapter->securitypriv.ndisencryptstatus = + Ndis802_11Encryption1Enabled; + break; + } + + { /* handle wps_ie */ + uint wps_ielen; + u8 *wps_ie; + + wps_ie = rtw_get_wps_ie23a(buf, ielen, NULL, &wps_ielen); + if (wps_ie && wps_ielen > 0) { + DBG_8723A("got wps_ie, wps_ielen:%u\n", wps_ielen); + padapter->securitypriv.wps_ie_len = + wps_ielen < + MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN; + memcpy(padapter->securitypriv.wps_ie, wps_ie, + padapter->securitypriv.wps_ie_len); + set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); + } else { + _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); + } + } + +#ifdef CONFIG_8723AU_P2P + { /* check p2p_ie for assoc req; */ + uint p2p_ielen = 0; + u8 *p2p_ie; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + p2p_ie = rtw_get_p2p_ie23a(buf, ielen, NULL, &p2p_ielen); + if (p2p_ie) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s p2p_assoc_req_ielen =%d\n", __func__, + p2p_ielen); +#endif + + if (pmlmepriv->p2p_assoc_req_ie) { + pmlmepriv->p2p_assoc_req_ie_len = 0; + kfree(pmlmepriv->p2p_assoc_req_ie); + pmlmepriv->p2p_assoc_req_ie = NULL; + } + + pmlmepriv->p2p_assoc_req_ie = + kmalloc(p2p_ielen, GFP_KERNEL); + if (pmlmepriv->p2p_assoc_req_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + goto exit; + } + memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen); + pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen; + } + } +#endif /* CONFIG_8723AU_P2P */ + +#ifdef CONFIG_8723AU_P2P + { /* check wfd_ie for assoc req; */ + uint wfd_ielen = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen)) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s wfd_assoc_req_ielen =%d\n", __func__, + wfd_ielen); +#endif + + if (pmlmepriv->wfd_assoc_req_ie) { + pmlmepriv->wfd_assoc_req_ie_len = 0; + kfree(pmlmepriv->wfd_assoc_req_ie); + pmlmepriv->wfd_assoc_req_ie = NULL; + } + + pmlmepriv->wfd_assoc_req_ie = + kmalloc(wfd_ielen, GFP_KERNEL); + if (pmlmepriv->wfd_assoc_req_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + goto exit; + } + rtw_get_wfd_ie(buf, ielen, pmlmepriv->wfd_assoc_req_ie, + &pmlmepriv->wfd_assoc_req_ie_len); + } + } +#endif /* CONFIG_8723AU_P2P */ + + /* TKIP and AES disallow multicast packets until installing group key */ + if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ || + padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ || + padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) + /* WPS open need to enable multicast */ + /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true)*/ + rtw_hal_set_hwreg23a(padapter, HW_VAR_OFF_RCR_AM, null_addr); + + RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, + ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->" + "securitypriv.ndisencryptstatus =%d padapter->" + "securitypriv.ndisauthtype =%d\n", pairwise_cipher, + padapter->securitypriv.ndisencryptstatus, + padapter->securitypriv.ndisauthtype)); + +exit: + kfree(buf); + if (ret) + _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); + return ret; +} + +static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + int ret = 0; + struct list_head *phead, *plist, *ptmp; + struct wlan_network *pnetwork = NULL; + enum ndis_802_11_auth_mode authmode; + struct cfg80211_ssid ndis_ssid; + u8 *dst_ssid; + u8 *src_ssid; + u8 *dst_bssid; + const u8 *src_bssid; + /* u8 matched_by_bssid = false; */ + /* u8 matched_by_ssid = false; */ + u8 matched = false; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct rtw_queue *queue = &pmlmepriv->scanned_queue; + + DBG_8723A("=>" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + DBG_8723A("privacy =%d, key =%p, key_len =%d, key_idx =%d\n", + sme->privacy, sme->key, sme->key_len, sme->key_idx); + + if (wdev_to_priv(padapter->rtw_wdev)->block) { + ret = -EBUSY; + DBG_8723A("%s wdev_priv.block is set\n", __func__); + goto exit; + } + + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = -EPERM; + goto exit; + } + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + ret = -EPERM; + goto exit; + } + + if (!sme->ssid || !sme->ssid_len) { + ret = -EINVAL; + goto exit; + } + + if (sme->ssid_len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto exit; + } + + memset(&ndis_ssid, 0, sizeof(struct cfg80211_ssid)); + ndis_ssid.ssid_len = sme->ssid_len; + memcpy(ndis_ssid.ssid, sme->ssid, sme->ssid_len); + + DBG_8723A("ssid =%s, len =%zu\n", ndis_ssid.ssid, sme->ssid_len); + + if (sme->bssid) + DBG_8723A("bssid =" MAC_FMT "\n", MAC_ARG(sme->bssid)); + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { + ret = -EBUSY; + DBG_8723A("%s, fw_state = 0x%x, goto exit\n", __func__, + pmlmepriv->fw_state); + goto exit; + } + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { + rtw_scan_abort23a(padapter); + } + + spin_lock_bh(&queue->lock); + + phead = get_list_head(queue); + + list_for_each_safe(plist, ptmp, phead) { + pnetwork = container_of(plist, struct wlan_network, list); + + dst_ssid = pnetwork->network.Ssid.ssid; + dst_bssid = pnetwork->network.MacAddress; + + if (sme->bssid) { + if (memcmp(pnetwork->network.MacAddress, + sme->bssid, ETH_ALEN)) + continue; + } + + if (sme->ssid && sme->ssid_len) { + if (pnetwork->network.Ssid.ssid_len != sme->ssid_len || + memcmp(pnetwork->network.Ssid.ssid, sme->ssid, + sme->ssid_len)) + continue; + } + + if (sme->bssid) { + src_bssid = sme->bssid; + + if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) { + DBG_8723A("matched by bssid\n"); + + ndis_ssid.ssid_len = + pnetwork->network.Ssid.ssid_len; + memcpy(ndis_ssid.ssid, + pnetwork->network.Ssid.ssid, + pnetwork->network.Ssid.ssid_len); + + matched = true; + break; + } + + } else if (sme->ssid && sme->ssid_len) { + src_ssid = ndis_ssid.ssid; + + if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.ssid_len)) && + (pnetwork->network.Ssid.ssid_len == + ndis_ssid.ssid_len)) { + DBG_8723A("matched by ssid\n"); + matched = true; + break; + } + } + } + + spin_unlock_bh(&queue->lock); + + if (!matched || (pnetwork == NULL)) { + ret = -ENOENT; + DBG_8723A("connect, matched == false, goto exit\n"); + goto exit; + } + + if (rtw_set_802_11_infrastructure_mode23a + (padapter, pnetwork->network.InfrastructureMode) == false) { + ret = -EPERM; + goto exit; + } + + psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; + psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; + psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; + + ret = + rtw_cfg80211_set_wpa_version(psecuritypriv, + sme->crypto.wpa_versions); + if (ret < 0) + goto exit; + + ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type); + + if (ret < 0) + goto exit; + + DBG_8723A("%s, ie_len =%zu\n", __func__, sme->ie_len); + + ret = rtw_cfg80211_set_wpa_ie(padapter, sme->ie, sme->ie_len); + if (ret < 0) + goto exit; + + if (sme->crypto.n_ciphers_pairwise) { + ret = rtw_cfg80211_set_cipher(psecuritypriv, + sme->crypto.ciphers_pairwise[0], + true); + if (ret < 0) + goto exit; + } + + /* For WEP Shared auth */ + if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared || + psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && + sme->key) { + u32 wep_key_idx, wep_key_len, wep_total_len; + struct ndis_802_11_wep *pwep = NULL; + DBG_8723A("%s(): Shared/Auto WEP\n", __func__); + + wep_key_idx = sme->key_idx; + wep_key_len = sme->key_len; + + if (sme->key_idx > WEP_KEYS) { + ret = -EINVAL; + goto exit; + } + + if (wep_key_len > 0) { + wep_key_len = wep_key_len <= 5 ? 5 : 13; + wep_total_len = + wep_key_len + + offsetof(struct ndis_802_11_wep, KeyMaterial); + pwep = (struct ndis_802_11_wep *)kmalloc(wep_total_len, + GFP_KERNEL); + if (pwep == NULL) { + DBG_8723A(" wpa_set_encryption: pwep " + "allocate fail !!!\n"); + ret = -ENOMEM; + goto exit; + } + + memset(pwep, 0, wep_total_len); + + pwep->KeyLength = wep_key_len; + pwep->Length = wep_total_len; + + if (wep_key_len == 13) { + padapter->securitypriv.dot11PrivacyAlgrthm = + _WEP104_; + padapter->securitypriv.dot118021XGrpPrivacy = + _WEP104_; + } + } else { + ret = -EINVAL; + goto exit; + } + + pwep->KeyIndex = wep_key_idx; + pwep->KeyIndex |= 0x80000000; + + memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength); + + if (rtw_set_802_11_add_wep23a(padapter, pwep) == (u8) _FAIL) { + ret = -EOPNOTSUPP; + } + + kfree(pwep); + + if (ret < 0) + goto exit; + } + + ret = rtw_cfg80211_set_cipher(psecuritypriv, + sme->crypto.cipher_group, false); + if (ret < 0) + return ret; + + if (sme->crypto.n_akm_suites) { + ret = rtw_cfg80211_set_key_mgt(psecuritypriv, + sme->crypto.akm_suites[0]); + if (ret < 0) + goto exit; + } + + authmode = psecuritypriv->ndisauthtype; + rtw_set_802_11_authentication_mode23a(padapter, authmode); + + /* rtw_set_802_11_encryption_mode(padapter, + padapter->securitypriv.ndisencryptstatus); */ + + if (rtw_set_802_11_ssid23a(padapter, &ndis_ssid) == false) { + ret = -1; + goto exit; + } + + DBG_8723A("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, " + "dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm, + psecuritypriv->dot11PrivacyAlgrthm, + psecuritypriv->dot118021XGrpPrivacy); + +exit: + + DBG_8723A("<=%s, ret %d\n", __func__, ret); + + return ret; +} + +static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, + u16 reason_code) +{ + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + rtw_set_roaming(padapter, 0); + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { + rtw_scan_abort23a(padapter); + LeaveAllPowerSaveMode23a(padapter); + rtw_disassoc_cmd23a(padapter, 500, false); + + DBG_8723A("%s...call rtw_indicate_disconnect23a\n", __func__); + + padapter->mlmepriv.not_indic_disco = true; + rtw_indicate_disconnect23a(padapter); + padapter->mlmepriv.not_indic_disco = false; + + rtw_free_assoc_resources23a(padapter, 1); + } + + return 0; +} + +static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + DBG_8723A("%s\n", __func__); + return 0; +} + +static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, int *dbm) +{ + DBG_8723A("%s\n", __func__); + *dbm = (12); + return 0; +} + +inline bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter) +{ + struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(adapter->rtw_wdev); + return rtw_wdev_priv->power_mgmt; +} + +static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy, + struct net_device *ndev, + bool enabled, int timeout) +{ + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(padapter->rtw_wdev); + + DBG_8723A(FUNC_NDEV_FMT " enabled:%u, timeout:%d\n", + FUNC_NDEV_ARG(ndev), enabled, timeout); + + rtw_wdev_priv->power_mgmt = enabled; + + if (!enabled) + LPS_Leave23a(padapter); + + return 0; +} + +static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, + struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + u8 index, blInserted = false; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 strZeroMacAddress[ETH_ALEN] = { 0x00 }; + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); + + if (!memcmp(pmksa->bssid, strZeroMacAddress, ETH_ALEN)) { + return -EINVAL; + } + + blInserted = false; + + /* overwrite PMKID */ + for (index = 0; index < NUM_PMKID_CACHE; index++) { + if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, + pmksa->bssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => rewrite with + new PMKID. */ + DBG_8723A(FUNC_NDEV_FMT + " BSSID exists in the PMKList.\n", + FUNC_NDEV_ARG(netdev)); + + memcpy(psecuritypriv->PMKIDList[index].PMKID, + pmksa->pmkid, WLAN_PMKID_LEN); + psecuritypriv->PMKIDList[index].bUsed = true; + psecuritypriv->PMKIDIndex = index + 1; + blInserted = true; + break; + } + } + + if (!blInserted) { + /* Find a new entry */ + DBG_8723A(FUNC_NDEV_FMT + " Use the new entry index = %d for this PMKID.\n", + FUNC_NDEV_ARG(netdev), psecuritypriv->PMKIDIndex); + + memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. + Bssid, pmksa->bssid, ETH_ALEN); + memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex]. + PMKID, pmksa->pmkid, WLAN_PMKID_LEN); + + psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = + true; + psecuritypriv->PMKIDIndex++; + if (psecuritypriv->PMKIDIndex == 16) { + psecuritypriv->PMKIDIndex = 0; + } + } + + return 0; +} + +static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, + struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + u8 index, bMatched = false; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); + + for (index = 0; index < NUM_PMKID_CACHE; index++) { + if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, + pmksa->bssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ + memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, + ETH_ALEN); + memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, + WLAN_PMKID_LEN); + psecuritypriv->PMKIDList[index].bUsed = false; + bMatched = true; + break; + } + } + + if (false == bMatched) { + DBG_8723A(FUNC_NDEV_FMT " do not have matched BSSID\n", + FUNC_NDEV_ARG(netdev)); + return -EINVAL; + } + + return 0; +} + +static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, + struct net_device *netdev) +{ + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev)); + + memset(&psecuritypriv->PMKIDList[0], 0x00, + sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + psecuritypriv->PMKIDIndex = 0; + + return 0; +} + +#ifdef CONFIG_8723AU_AP_MODE +void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter, + u8 *pmgmt_frame, uint frame_len) +{ + s32 freq; + int channel; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct net_device *ndev = padapter->pnetdev; + + DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name); + +#if defined(RTW_USE_CFG80211_STA_EVENT) + { + struct station_info sinfo; + u8 ie_offset; + if (ieee80211_is_assoc_req(hdr->frame_control)) + ie_offset = _ASOCREQ_IE_OFFSET_; + else /* WIFI_REASSOCREQ */ + ie_offset = _REASOCREQ_IE_OFFSET_; + + sinfo.filled = 0; + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset; + sinfo.assoc_req_ies_len = + frame_len - WLAN_HDR_A3_LEN - ie_offset; + cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC); + } +#else /* defined(RTW_USE_CFG80211_STA_EVENT) */ + channel = pmlmeext->cur_channel; + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, + GFP_ATOMIC); +#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ +} + +void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter, + unsigned char *da, + unsigned short reason) +{ + s32 freq; + int channel; + u8 *pmgmt_frame; + uint frame_len; + struct ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + u8 mgmt_buf[128] = { 0 }; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct net_device *ndev = padapter->pnetdev; + + DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name); + +#if defined(RTW_USE_CFG80211_STA_EVENT) + cfg80211_del_sta(ndev, da, GFP_ATOMIC); +#else /* defined(RTW_USE_CFG80211_STA_EVENT) */ + channel = pmlmeext->cur_channel; + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + pmgmt_frame = mgmt_buf; + pwlanhdr = (struct ieee80211_hdr *)pmgmt_frame; + + fctrl = &pwlanhdr->frame_control; + *(fctrl) = 0; + + memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr2, da, ETH_ALEN); + memcpy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pmgmt_frame, WIFI_DEAUTH); + + pmgmt_frame += sizeof(struct ieee80211_hdr_3addr); + frame_len = sizeof(struct ieee80211_hdr_3addr); + + reason = cpu_to_le16(reason); + pmgmt_frame = rtw_set_fixed_ie23a(pmgmt_frame, + WLAN_REASON_PREV_AUTH_NOT_VALID, + (unsigned char *)&reason, &frame_len); + + rtw_cfg80211_rx_mgmt(padapter, freq, 0, mgmt_buf, frame_len, + GFP_ATOMIC); +#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */ +} + +static int rtw_cfg80211_monitor_if_open(struct net_device *ndev) +{ + int ret = 0; + + DBG_8723A("%s\n", __func__); + + return ret; +} + +static int rtw_cfg80211_monitor_if_close(struct net_device *ndev) +{ + int ret = 0; + + DBG_8723A("%s\n", __func__); + + return ret; +} + +static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, + struct net_device *ndev) +{ + int ret = 0; + int rtap_len; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *rtap_hdr; + struct rtw_adapter *padapter = netdev_priv(ndev); + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + if (unlikely(rtap_hdr->it_version)) + goto fail; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (unlikely(skb->len < rtap_len)) + goto fail; + + if (rtap_len != 14) { + DBG_8723A("radiotap len (should be 14): %d\n", rtap_len); + goto fail; + } + + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + dot11_hdr = (struct ieee80211_hdr *)skb->data; + /* Check if the QoS bit is set */ + if (ieee80211_is_data(dot11_hdr->frame_control)) { + /* Check if this ia a Wireless Distribution System (WDS) frame + * which has 4 MAC addresses + */ + if (ieee80211_is_data_qos(dot11_hdr->frame_control)) + qos_len = IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_a4(dot11_hdr->frame_control)) + dot11_hdr_len += 6; + + memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); + memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); + + /* + * Skip the 802.11 header, QoS (if any) and SNAP, + * but leave spaces for two MAC addresses + */ + skb_pull(skb, dot11_hdr_len + qos_len + snap_len - + ETH_ALEN * 2); + pdata = (unsigned char *)skb->data; + memcpy(pdata, dst_mac_addr, ETH_ALEN); + memcpy(pdata + ETH_ALEN, src_mac_addr, ETH_ALEN); + + DBG_8723A("should be eapol packet\n"); + + /* Use the real net device to transmit the packet */ + ret = rtw_xmit23a_entry23a(skb, padapter->pnetdev); + + return ret; + + } else if (ieee80211_is_action(dot11_hdr->frame_control)) { + /* only for action frames */ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + /* u8 category, action, OUI_Subtype, dialogToken = 0; */ + /* unsigned char *frame_body; */ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u32 len = skb->len; + u8 category, action; + int type = -1; + + if (rtw_action_frame_parse23a(skb->data, len, &category, + &action) == false) { + DBG_8723A(FUNC_NDEV_FMT " frame_control:0x%x\n", + FUNC_NDEV_ARG(ndev), + le16_to_cpu(dot11_hdr->frame_control)); + goto fail; + } + + DBG_8723A("RTW_Tx:da =" MAC_FMT " via " FUNC_NDEV_FMT "\n", + MAC_ARG(dot11_hdr->addr1), FUNC_NDEV_ARG(ndev)); +#ifdef CONFIG_8723AU_P2P + type = rtw_p2p_check_frames(padapter, skb->data, len, true); + if (type >= 0) + goto dump; +#endif + if (category == WLAN_CATEGORY_PUBLIC) + DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); + else + DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, + action); +dump: + /* starting alloc mgmt frame to dump it */ + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (pmgntframe == NULL) + goto fail; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->retry_ctrl = false; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + memcpy(pframe, skb->data, len); +#ifdef CONFIG_8723AU_P2P + if (type >= 0) { + struct wifi_display_info *pwfd_info; + + pwfd_info = padapter->wdinfo.wfd_info; + + if (pwfd_info->wfd_enable) + rtw_append_wfd_ie(padapter, pframe, &len); + } +#endif /* CONFIG_8723AU_P2P */ + pattrib->pktlen = len; + + /* update seq number */ + pmlmeext->mgnt_seq = le16_to_cpu(dot11_hdr->seq_ctrl) >> 4; + pattrib->seqnum = pmlmeext->mgnt_seq; + pmlmeext->mgnt_seq++; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe23a(padapter, pmgntframe); + } + +fail: + + dev_kfree_skb(skb); + + return 0; +} + +static int +rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr) +{ + int ret = 0; + + DBG_8723A("%s\n", __func__); + + return ret; +} + +static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { + .ndo_open = rtw_cfg80211_monitor_if_open, + .ndo_stop = rtw_cfg80211_monitor_if_close, + .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry, + .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address, +}; + +static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name, + struct net_device **ndev) +{ + int ret = 0; + struct net_device *mon_ndev = NULL; + struct wireless_dev *mon_wdev = NULL; + struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); + + if (!name) { + DBG_8723A(FUNC_ADPT_FMT " without specific name\n", + FUNC_ADPT_ARG(padapter)); + ret = -EINVAL; + goto out; + } + + if (pwdev_priv->pmon_ndev) { + DBG_8723A(FUNC_ADPT_FMT " monitor interface exist: " NDEV_FMT + "\n", FUNC_ADPT_ARG(padapter), + NDEV_ARG(pwdev_priv->pmon_ndev)); + ret = -EBUSY; + goto out; + } + + mon_ndev = alloc_etherdev(sizeof(struct rtw_adapter)); + if (!mon_ndev) { + DBG_8723A(FUNC_ADPT_FMT " allocate ndev fail\n", + FUNC_ADPT_ARG(padapter)); + ret = -ENOMEM; + goto out; + } + + mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(mon_ndev->name, name, IFNAMSIZ); + mon_ndev->name[IFNAMSIZ - 1] = 0; + mon_ndev->destructor = rtw_ndev_destructor; + + mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops; + + /* wdev */ + mon_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!mon_wdev) { + DBG_8723A(FUNC_ADPT_FMT " allocate mon_wdev fail\n", + FUNC_ADPT_ARG(padapter)); + ret = -ENOMEM; + goto out; + } + + mon_wdev->wiphy = padapter->rtw_wdev->wiphy; + mon_wdev->netdev = mon_ndev; + mon_wdev->iftype = NL80211_IFTYPE_MONITOR; + mon_ndev->ieee80211_ptr = mon_wdev; + + ret = register_netdevice(mon_ndev); + if (ret) { + goto out; + } + + *ndev = pwdev_priv->pmon_ndev = mon_ndev; + memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ + 1); + +out: + if (ret) { + kfree(mon_wdev); + mon_wdev = NULL; + } + + if (ret && mon_ndev) { + free_netdev(mon_ndev); + *ndev = mon_ndev = NULL; + } + + return ret; +} + +static struct wireless_dev * +cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + int ret = 0; + struct net_device *ndev = NULL; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + + DBG_8723A(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", + FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type); + + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + ret = -ENODEV; + break; + case NL80211_IFTYPE_MONITOR: + ret = + rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev); + break; + + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + ret = -ENODEV; + break; + + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + ret = -ENODEV; + break; + default: + ret = -ENODEV; + DBG_8723A("Unsupported interface type\n"); + break; + } + + DBG_8723A(FUNC_ADPT_FMT " ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter), + ndev, ret); + + return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret); +} + +static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct rtw_wdev_priv *pwdev_priv = + (struct rtw_wdev_priv *)wiphy_priv(wiphy); + struct net_device *ndev; + ndev = wdev ? wdev->netdev : NULL; + + if (!ndev) + goto exit; + + unregister_netdevice(ndev); + + if (ndev == pwdev_priv->pmon_ndev) { + pwdev_priv->pmon_ndev = NULL; + pwdev_priv->ifname_mon[0] = '\0'; + DBG_8723A(FUNC_NDEV_FMT " remove monitor interface\n", + FUNC_NDEV_ARG(ndev)); + } + +exit: + return 0; +} + +static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head, + size_t head_len, const u8 *tail, size_t tail_len) +{ + int ret = 0; + u8 *pbuf = NULL; + uint len, wps_ielen = 0; + uint p2p_ielen = 0; + u8 got_p2p_ie = false; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + /* struct sta_priv *pstapriv = &padapter->stapriv; */ + + DBG_8723A("%s beacon_head_len =%zu, beacon_tail_len =%zu\n", + __func__, head_len, tail_len); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) + return -EINVAL; + + if (head_len < 24) + return -EINVAL; + + pbuf = kzalloc(head_len + tail_len, GFP_KERNEL); + if (!pbuf) + return -ENOMEM; + /* 24 = beacon header len. */ + memcpy(pbuf, (void *)head + 24, head_len - 24); + memcpy(pbuf + head_len - 24, (void *)tail, tail_len); + + len = head_len + tail_len - 24; + + /* check wps ie if inclued */ + if (rtw_get_wps_ie23a + (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, + &wps_ielen)) + DBG_8723A("add bcn, wps_ielen =%d\n", wps_ielen); + +#ifdef CONFIG_8723AU_P2P + /* check p2p ie if inclued */ + if (rtw_get_p2p_ie23a + (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, + &p2p_ielen)) { + DBG_8723A("got p2p_ie, len =%d\n", p2p_ielen); + got_p2p_ie = true; + } +#endif + + /* pbss_network->IEs will not include p2p_ie, wfd ie */ + rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, + P2P_OUI23A, 4); + rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, + WFD_OUI23A, 4); + + if (rtw_check_beacon_data23a(adapter, pbuf, len) == _SUCCESS) { +#ifdef CONFIG_8723AU_P2P + /* check p2p if enable */ + if (got_p2p_ie == true) { + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + DBG_8723A("Enable P2P function for the first " + "time\n"); + rtw_p2p_enable23a(adapter, P2P_ROLE_GO); + wdev_to_priv(adapter->rtw_wdev)->p2p_enabled = + true; + } else { + del_timer_sync(&pwdinfo->find_phase_timer); + del_timer_sync(&pwdinfo-> + restore_p2p_state_timer); + del_timer_sync(&pwdinfo->pre_tx_scan_timer); + + DBG_8723A("enter GO Mode, p2p_ielen =%d\n", + p2p_ielen); + + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + pwdinfo->intent = 15; + } + + pwdinfo->operating_channel = pmlmeext->cur_channel; + } +#endif /* CONFIG_8723AU_P2P */ + + ret = 0; + + } else { + ret = -EINVAL; + } + + kfree(pbuf); + + return ret; +} + +static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ap_settings *settings) +{ + int ret = 0; + struct rtw_adapter *adapter = wiphy_to_adapter(wiphy); + + DBG_8723A(FUNC_NDEV_FMT " hidden_ssid:%d, auth_type:%d\n", + FUNC_NDEV_ARG(ndev), settings->hidden_ssid, + settings->auth_type); + + ret = rtw_add_beacon(adapter, settings->beacon.head, + settings->beacon.head_len, settings->beacon.tail, + settings->beacon.tail_len); + + adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode = + settings->hidden_ssid; + + if (settings->ssid && settings->ssid_len) { + struct wlan_bssid_ex *pbss_network = + &adapter->mlmepriv.cur_network.network; + struct wlan_bssid_ex *pbss_network_ext = + &adapter->mlmeextpriv.mlmext_info.network; + + if (0) + DBG_8723A(FUNC_ADPT_FMT + " ssid:(%s,%d), from ie:(%s,%d)\n", + FUNC_ADPT_ARG(adapter), settings->ssid, + (int)settings->ssid_len, + pbss_network->Ssid.ssid, + pbss_network->Ssid.ssid_len); + + memcpy(pbss_network->Ssid.ssid, (void *)settings->ssid, + settings->ssid_len); + pbss_network->Ssid.ssid_len = settings->ssid_len; + memcpy(pbss_network_ext->Ssid.ssid, (void *)settings->ssid, + settings->ssid_len); + pbss_network_ext->Ssid.ssid_len = settings->ssid_len; + + if (0) + DBG_8723A(FUNC_ADPT_FMT + " after ssid:(%s,%d), (%s,%d)\n", + FUNC_ADPT_ARG(adapter), + pbss_network->Ssid.ssid, + pbss_network->Ssid.ssid_len, + pbss_network_ext->Ssid.ssid, + pbss_network_ext->Ssid.ssid_len); + } + + return ret; +} + +static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_beacon_data *info) +{ + int ret = 0; + struct rtw_adapter *adapter = wiphy_to_adapter(wiphy); + + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, + info->tail_len); + + return ret; +} + +static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} + +static int cfg80211_rtw_add_station(struct wiphy *wiphy, + struct net_device *ndev, u8 *mac, + struct station_parameters *params) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + return 0; +} + +static int cfg80211_rtw_del_station(struct wiphy *wiphy, + struct net_device *ndev, u8 *mac) +{ + int ret = 0; + struct list_head *phead, *plist, *ptmp; + u8 updated = 0; + struct sta_info *psta; + struct rtw_adapter *padapter = netdev_priv(ndev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + + DBG_8723A("+" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) { + DBG_8723A("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", + __func__); + return -EINVAL; + } + + if (!mac) { + DBG_8723A("flush all sta, and cam_entry\n"); + + flush_all_cam_entry23a(padapter); /* clear CAM */ + + ret = rtw_sta_flush23a(padapter); + + return ret; + } + + DBG_8723A("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac)); + + if (is_broadcast_ether_addr(mac)) + return -EINVAL; + + spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + + /* check asoc_queue */ + list_for_each_safe(plist, ptmp, phead) { + psta = container_of(plist, struct sta_info, asoc_list); + + if (!memcmp(mac, psta->hwaddr, ETH_ALEN)) { + if (psta->dot8021xalg == 1 && + psta->bpairwise_key_installed == false) { + DBG_8723A("%s, sta's dot8021xalg = 1 and " + "key_installed = false\n", __func__); + } else { + DBG_8723A("free psta =%p, aid =%d\n", psta, + psta->aid); + + list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + + /* spin_unlock_bh(&pstapriv->asoc_list_lock); */ + updated = + ap_free_sta23a(padapter, psta, true, + WLAN_REASON_DEAUTH_LEAVING); + /* spin_lock_bh(&pstapriv->asoc_list_lock); */ + + psta = NULL; + + break; + } + } + } + + spin_unlock_bh(&pstapriv->asoc_list_lock); + + associated_clients_update23a(padapter, updated); + + DBG_8723A("-" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + return ret; +} + +static int cfg80211_rtw_change_station(struct wiphy *wiphy, + struct net_device *ndev, u8 *mac, + struct station_parameters *params) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} + +static int cfg80211_rtw_dump_station(struct wiphy *wiphy, + struct net_device *ndev, int idx, u8 *mac, + struct station_info *sinfo) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + + /* TODO: dump scanned queue */ + + return -ENOENT; +} + +static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, + struct bss_parameters *params) +{ + DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); + return 0; +} +#endif /* CONFIG_8723AU_AP_MODE */ + +void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, + uint frame_len) +{ + int type; + s32 freq; + int channel; + u8 category, action; + + channel = rtw_get_oper_ch23a(padapter); + + DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); +#ifdef CONFIG_8723AU_P2P + type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); + if (type >= 0) + goto indicate; +#endif + rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); + DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); + +indicate: + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, + GFP_ATOMIC); +} + +void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, + u8 *pmgmt_frame, uint frame_len) +{ + int type; + s32 freq; + int channel; + u8 category, action; + + channel = rtw_get_oper_ch23a(padapter); + + DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); +#ifdef CONFIG_8723AU_P2P + type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false); + if (type >= 0) { + switch (type) { + case P2P_GO_NEGO_CONF: + case P2P_PROVISION_DISC_RESP: + rtw_clear_scan_deny(padapter); + } + goto indicate; + } +#endif + rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); + DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); + +indicate: + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len, + GFP_ATOMIC); +} + +void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame, + uint frame_len, const char *msg) +{ + s32 freq; + int channel; + u8 category, action; + + channel = rtw_get_oper_ch23a(adapter); + + rtw_action_frame_parse23a(frame, frame_len, &category, &action); + + DBG_8723A("RTW_Rx:cur_ch =%d\n", channel); + if (msg) + DBG_8723A("RTW_Rx:%s\n", msg); + else + DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, + action); + + if (channel <= RTW_CH_MAX_2G_CHANNEL) + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(channel, + IEEE80211_BAND_5GHZ); + + rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); +} + +#ifdef CONFIG_8723AU_P2P +void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, + const u8 *buf, size_t len) +{ + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; + u8 wpsie[255] = { 0x00 }, p2p_ie[255] = { 0x00 }; + uint p2p_ielen = 0; + uint wpsielen = 0; + u32 devinfo_contentlen = 0; + u8 devinfo_content[64] = { 0x00 }; + u16 capability = 0; + uint capability_len = 0; + + unsigned char category = WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = 1; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_REQ; + u32 p2pielen = 0; +#ifdef CONFIG_8723AU_P2P + u32 wfdielen = 0; +#endif /* CONFIG_8723AU_P2P */ + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct ieee80211_hdr *pwlanhdr, *hdr; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 *frame_body = + (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr)); + size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr); + + DBG_8723A("[%s] In\n", __func__); + + hdr = (struct ieee80211_hdr *)buf; + /* prepare for building provision_request frame */ + memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, hdr->addr1, ETH_ALEN); + memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, hdr->addr1, ETH_ALEN); + + pwdinfo->tx_prov_disc_info.wps_config_method_request = + WPS_CM_PUSH_BUTTON; + + rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, + &wpsielen); + rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, + (u8 *)&wps_devicepassword_id, + &wps_devicepassword_id_len); + wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); + + switch (wps_devicepassword_id) { + case WPS_DPID_PIN: + pwdinfo->tx_prov_disc_info.wps_config_method_request = + WPS_CM_LABEL; + break; + case WPS_DPID_USER_SPEC: + pwdinfo->tx_prov_disc_info.wps_config_method_request = + WPS_CM_DISPLYA; + break; + case WPS_DPID_MACHINE_SPEC: + break; + case WPS_DPID_REKEY: + break; + case WPS_DPID_PBC: + pwdinfo->tx_prov_disc_info.wps_config_method_request = + WPS_CM_PUSH_BUTTON; + break; + case WPS_DPID_REGISTRAR_SPEC: + pwdinfo->tx_prov_disc_info.wps_config_method_request = + WPS_CM_KEYPAD; + break; + default: + break; + } + + if (rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, + frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, + p2p_ie, &p2p_ielen)) { + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, + P2P_ATTR_DEVICE_INFO, devinfo_content, + &devinfo_contentlen); + rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, + (u8 *)&capability, &capability_len); + } + + /* start to build provision_request frame */ + memset(wpsie, 0, sizeof(wpsie)); + memset(p2p_ie, 0, sizeof(p2p_ie)); + p2p_ielen = 0; + + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (pmgntframe == NULL) + return; + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct ieee80211_hdr *)pframe; + + pwlanhdr->frame_control = 0; + + memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr, + ETH_ALEN); + memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr, + ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + SetFrameSubType(pframe, WIFI_ACTION); + + pframe += sizeof(struct ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, + &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen); + pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen); + + /* build_prov_disc_request_p2p_ie23a */ + /* P2P OUI */ + p2pielen = 0; + p2p_ie[p2pielen++] = 0x50; + p2p_ie[p2pielen++] = 0x6F; + p2p_ie[p2pielen++] = 0x9A; + p2p_ie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110301 */ + /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Device Info */ + /* 3. Group ID ( When joining an operating P2P Group ) */ + + /* P2P Capability ATTR */ + /* Type: */ + p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + RTW_PUT_LE16(p2p_ie + p2pielen, 0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + /* Group Capability Bitmap, 1 byte */ + memcpy(p2p_ie + p2pielen, &capability, 2); + p2pielen += 2; + + /* Device Info ATTR */ + /* Type: */ + p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + RTW_PUT_LE16(p2p_ie + p2pielen, devinfo_contentlen); + p2pielen += 2; + + /* Value: */ + memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen); + p2pielen += devinfo_contentlen; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, + (unsigned char *)p2p_ie, &p2p_ielen); + pattrib->pktlen += p2p_ielen; + + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Config Method */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = + cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); + wpsielen += 2; + + pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, + (unsigned char *)wpsie, &pattrib->pktlen); + +#ifdef CONFIG_8723AU_P2P + wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + /* dump_mgntframe23a(padapter, pmgntframe); */ + if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) + DBG_8723A("%s, ack to\n", __func__); +} + +static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *channel, + unsigned int duration, u64 *cookie) +{ + s32 err = 0; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = + &padapter->cfg80211_wdinfo; + u8 remain_ch = + (u8) ieee80211_frequency_to_channel(channel->center_freq); + u8 ready_on_channel = false; + + DBG_8723A(FUNC_ADPT_FMT " ch:%u duration:%d\n", FUNC_ADPT_ARG(padapter), + remain_ch, duration); + + if (pcfg80211_wdinfo->is_ro_ch == true) { + DBG_8723A("%s, cancel ro ch timer\n", __func__); + + del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); + + p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); + } + + pcfg80211_wdinfo->is_ro_ch = true; + + if (_FAIL == rtw_pwr_wakeup(padapter)) { + err = -EFAULT; + goto exit; + } + + memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel, + sizeof(struct ieee80211_channel)); + pcfg80211_wdinfo->remain_on_ch_cookie = *cookie; + + rtw_scan_abort23a(padapter); + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); + wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true; + } else { + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, + rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); +#endif + } + + rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); + + if (duration < 400) + duration = duration * 3; /* extend from exper. */ + + pcfg80211_wdinfo->restore_channel = pmlmeext->cur_channel; + + if (rtw_ch_set_search_ch23a(pmlmeext->channel_set, remain_ch) >= 0) { + if (remain_ch != pmlmeext->cur_channel) { + ready_on_channel = true; + } + } else { + DBG_8723A("%s remain_ch:%u not in channel plan!!!!\n", + __func__, remain_ch); + } + + /* call this after other things have been done */ + if (ready_on_channel == true) { + if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { + pmlmeext->cur_channel = remain_ch; + + set_channel_bwmode23a(padapter, remain_ch, + HAL_PRIME_CHNL_OFFSET_DONT_CARE, + HT_CHANNEL_WIDTH_20); + } + } + DBG_8723A("%s, set ro ch timer, duration =%d\n", __func__, duration); + mod_timer(&pcfg80211_wdinfo->remain_on_ch_timer, + jiffies + msecs_to_jiffies(duration)); + + rtw_cfg80211_ready_on_channel(padapter, *cookie, channel, channel_type, + duration, GFP_KERNEL); + + pwdinfo->listen_channel = pmlmeext->cur_channel; + +exit: + if (err) + pcfg80211_wdinfo->is_ro_ch = false; + + return err; +} + +static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + s32 err = 0; + struct rtw_adapter *padapter = wiphy_to_adapter(wiphy); + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = + &padapter->cfg80211_wdinfo; + + DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); + + if (pcfg80211_wdinfo->is_ro_ch == true) { + DBG_8723A("%s, cancel ro ch timer\n", __func__); + del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); + p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); + } + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__, + rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); +#endif + pcfg80211_wdinfo->is_ro_ch = false; + + return err; +} + +#endif /* CONFIG_8723AU_P2P */ + +static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch, + const u8 *buf, size_t len) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + int ret = _FAIL; + bool ack = true; + struct ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + /* struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; */ + + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = -EFAULT; + goto exit; + } + + rtw_set_scan_deny(padapter, 1000); + + rtw_scan_abort23a(padapter); + + if (tx_ch != rtw_get_oper_ch23a(padapter)) { + if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) + pmlmeext->cur_channel = tx_ch; + set_channel_bwmode23a(padapter, tx_ch, + HAL_PRIME_CHNL_OFFSET_DONT_CARE, + HT_CHANNEL_WIDTH_20); + } + + /* starting alloc mgmt frame to dump it */ + pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); + if (pmgntframe == NULL) { + /* ret = -ENOMEM; */ + ret = _FAIL; + goto exit; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib23a(padapter, pattrib); + pattrib->retry_ctrl = false; + + memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET; + + memcpy(pframe, (void *)buf, len); + pattrib->pktlen = len; + + pwlanhdr = (struct ieee80211_hdr *)pframe; + /* update seq number */ + pmlmeext->mgnt_seq = le16_to_cpu(pwlanhdr->seq_ctrl) >> 4; + pattrib->seqnum = pmlmeext->mgnt_seq; + pmlmeext->mgnt_seq++; + +#ifdef CONFIG_8723AU_P2P + { + struct wifi_display_info *pwfd_info; + + pwfd_info = padapter->wdinfo.wfd_info; + + if (true == pwfd_info->wfd_enable) { + rtw_append_wfd_ie(padapter, pframe, &pattrib->pktlen); + } + } +#endif /* CONFIG_8723AU_P2P */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) { + ack = false; + ret = _FAIL; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, ack == _FAIL\n", __func__); +#endif + } else { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, ack =%d, ok!\n", __func__, ack); +#endif + ret = _SUCCESS; + } + +exit: + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, ret =%d\n", __func__, ret); +#endif + + return ret; +} + +static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) + struct ieee80211_channel *chan, + bool offchan, + unsigned int wait, + const u8 *buf, size_t len, + bool no_cck, bool dont_wait_for_ack, +#else + struct cfg80211_mgmt_tx_params *params, +#endif + u64 *cookie) +{ + struct rtw_adapter *padapter = + (struct rtw_adapter *)wiphy_to_adapter(wiphy); + struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); + int ret = 0; + int tx_ret; + u32 dump_limit = RTW_MAX_MGMT_TX_CNT; + u32 dump_cnt = 0; + bool ack = true; + u8 category, action; + int type = (-1); + unsigned long start = jiffies; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + size_t len = params->len; + struct ieee80211_channel *chan = params->chan; + const u8 *buf = params->buf; +#endif + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buf; + u8 tx_ch = (u8) ieee80211_frequency_to_channel(chan->center_freq); + + /* cookie generation */ + *cookie = (unsigned long)buf; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A(FUNC_ADPT_FMT " len =%zu, ch =%d" + "\n", FUNC_ADPT_ARG(padapter), len, tx_ch); +#endif /* CONFIG_DEBUG_CFG80211 */ + + /* indicate ack before issue frame to avoid racing with rsp frame */ + rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack, + GFP_KERNEL); + + if (rtw_action_frame_parse23a(buf, len, &category, &action) == false) { + DBG_8723A(FUNC_ADPT_FMT " frame_control:0x%x\n", + FUNC_ADPT_ARG(padapter), + le16_to_cpu(hdr->frame_control)); + goto exit; + } + + DBG_8723A("RTW_Tx:tx_ch =%d, da =" MAC_FMT "\n", tx_ch, + MAC_ARG(hdr->addr1)); +#ifdef CONFIG_8723AU_P2P + type = rtw_p2p_check_frames(padapter, buf, len, true); + if (type >= 0) + goto dump; +#endif + if (category == WLAN_CATEGORY_PUBLIC) + DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action)); + else + DBG_8723A("RTW_Tx:category(%u), action(%u)\n", + category, action); + +dump: + do { + dump_cnt++; + tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); + } while (dump_cnt < dump_limit && tx_ret != _SUCCESS); + + if (tx_ret != _SUCCESS || dump_cnt > 1) { + DBG_8723A(FUNC_ADPT_FMT " %s (%d/%d) in %d ms\n", + FUNC_ADPT_ARG(padapter), + tx_ret == _SUCCESS ? "OK" : "FAIL", dump_cnt, + dump_limit, jiffies_to_msecs(jiffies - start)); + } + + switch (type) { + case P2P_GO_NEGO_CONF: + rtw_clear_scan_deny(padapter); + break; + case P2P_INVIT_RESP: + if (pwdev_priv->invit_info.flags & BIT(0) + && pwdev_priv->invit_info.status == 0) { + DBG_8723A(FUNC_ADPT_FMT " agree with invitation of " + "persistent group\n", + FUNC_ADPT_ARG(padapter)); + rtw_set_scan_deny(padapter, 5000); + rtw_pwr_wakeup_ex(padapter, 5000); + rtw_clear_scan_deny(padapter); + } + break; + } + +exit: + return ret; +} + +static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A(FUNC_ADPT_FMT " frame_type:%x, reg:%d\n", + FUNC_ADPT_ARG(adapter), frame_type, reg); +#endif + + if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) + return; + + return; +} + +static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, + int len) +{ + int ret = 0; + uint wps_ielen = 0; + u8 *wps_ie; + u32 p2p_ielen = 0; + u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 }; + u8 *p2p_ie; + u32 wfd_ielen = 0; + struct rtw_adapter *padapter = netdev_priv(ndev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + DBG_8723A(FUNC_NDEV_FMT " ielen =%d\n", FUNC_NDEV_ARG(ndev), len); + + if (len > 0) { + wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); + if (wps_ie) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("bcn_wps_ielen =%d\n", wps_ielen); +#endif + + if (pmlmepriv->wps_beacon_ie) { + pmlmepriv->wps_beacon_ie_len = 0; + kfree(pmlmepriv->wps_beacon_ie); + pmlmepriv->wps_beacon_ie = NULL; + } + + pmlmepriv->wps_beacon_ie = + kmalloc(wps_ielen, GFP_KERNEL); + if (pmlmepriv->wps_beacon_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + } + memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen); + pmlmepriv->wps_beacon_ie_len = wps_ielen; + + update_beacon23a(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, + true); + } +#ifdef CONFIG_8723AU_P2P + p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); + if (p2p_ie) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("bcn_p2p_ielen =%d\n", p2p_ielen); +#endif + + if (pmlmepriv->p2p_beacon_ie) { + pmlmepriv->p2p_beacon_ie_len = 0; + kfree(pmlmepriv->p2p_beacon_ie); + pmlmepriv->p2p_beacon_ie = NULL; + } + + pmlmepriv->p2p_beacon_ie = + kmalloc(p2p_ielen, GFP_KERNEL); + if (pmlmepriv->p2p_beacon_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + } + + memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen); + pmlmepriv->p2p_beacon_ie_len = p2p_ielen; + } +#endif /* CONFIG_8723AU_P2P */ + + /* buf += p2p_ielen; */ + /* len -= p2p_ielen; */ + +#ifdef CONFIG_8723AU_P2P + if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("bcn_wfd_ielen =%d\n", wfd_ielen); +#endif + + if (pmlmepriv->wfd_beacon_ie) { + pmlmepriv->wfd_beacon_ie_len = 0; + kfree(pmlmepriv->wfd_beacon_ie); + pmlmepriv->wfd_beacon_ie = NULL; + } + + pmlmepriv->wfd_beacon_ie = + kmalloc(wfd_ielen, GFP_KERNEL); + if (pmlmepriv->wfd_beacon_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_beacon_ie, + &pmlmepriv->wfd_beacon_ie_len); + } +#endif /* CONFIG_8723AU_P2P */ + + pmlmeext->bstart_bss = true; + + } + + return ret; +} + +static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, + char *buf, int len) +{ + struct rtw_adapter *padapter = netdev_priv(net); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + int ret = 0; + uint wps_ielen = 0; + u8 *wps_ie; + u32 p2p_ielen = 0; + u8 *p2p_ie; + u32 wfd_ielen = 0; + + if (len > 0) { + wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); + if (wps_ie) { + uint attr_contentlen = 0; + u16 uconfig_method, *puconfig_method = NULL; + + if (pmlmepriv->wps_probe_resp_ie) { + pmlmepriv->wps_probe_resp_ie_len = 0; + kfree(pmlmepriv->wps_probe_resp_ie); + pmlmepriv->wps_probe_resp_ie = NULL; + } + + pmlmepriv->wps_probe_resp_ie = + kmalloc(wps_ielen, GFP_KERNEL); + if (pmlmepriv->wps_probe_resp_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + + /* add PUSH_BUTTON config_method by driver self in + wpsie of probe_resp at GO Mode */ + puconfig_method = (u16 *)rtw_get_wps_attr_content23a(wps_ie, wps_ielen, + WPS_ATTR_CONF_METHOD, + NULL, + &attr_contentlen); + if (puconfig_method) { + uconfig_method = WPS_CM_PUSH_BUTTON; + uconfig_method = cpu_to_be16(uconfig_method); + + *puconfig_method |= uconfig_method; + } + + memcpy(pmlmepriv->wps_probe_resp_ie, wps_ie, wps_ielen); + pmlmepriv->wps_probe_resp_ie_len = wps_ielen; + + } + + /* buf += wps_ielen; */ + /* len -= wps_ielen; */ + +#ifdef CONFIG_8723AU_P2P + p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); + if (p2p_ie) { + u8 is_GO = false; + u32 attr_contentlen = 0; + u16 cap_attr = 0; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("probe_resp_p2p_ielen =%d\n", p2p_ielen); +#endif + + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, + P2P_ATTR_CAPABILITY, + (u8 *) &cap_attr, + (uint *) &attr_contentlen)) { + u8 grp_cap = 0; + /* DBG_8723A( "[%s] Got P2P Capability Attr!!\n", __func__ ); */ + cap_attr = le16_to_cpu(cap_attr); + grp_cap = (u8) ((cap_attr >> 8) & 0xff); + + is_GO = (grp_cap & BIT(0)) ? true : false; + + if (is_GO) + DBG_8723A + ("Got P2P Capability Attr, grp_cap" + "= 0x%x, is_GO\n", grp_cap); + } + + if (is_GO == false) { + if (pmlmepriv->p2p_probe_resp_ie) { + pmlmepriv->p2p_probe_resp_ie_len = 0; + kfree(pmlmepriv->p2p_probe_resp_ie); + pmlmepriv->p2p_probe_resp_ie = NULL; + } + + pmlmepriv->p2p_probe_resp_ie = + kmalloc(p2p_ielen, GFP_KERNEL); + if (pmlmepriv->p2p_probe_resp_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + } + memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie, + p2p_ielen); + pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen; + } else { + if (pmlmepriv->p2p_go_probe_resp_ie) { + pmlmepriv->p2p_go_probe_resp_ie_len = 0; + kfree(pmlmepriv->p2p_go_probe_resp_ie); + pmlmepriv->p2p_go_probe_resp_ie = NULL; + } + + pmlmepriv->p2p_go_probe_resp_ie = + kmalloc(p2p_ielen, GFP_KERNEL); + if (pmlmepriv->p2p_go_probe_resp_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + memcpy(pmlmepriv->p2p_go_probe_resp_ie, + p2p_ie, p2p_ielen); + pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen; + } + } +#endif /* CONFIG_8723AU_P2P */ + + /* buf += p2p_ielen; */ + /* len -= p2p_ielen; */ + +#ifdef CONFIG_8723AU_P2P + if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) { +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("probe_resp_wfd_ielen =%d\n", wfd_ielen); +#endif + + if (pmlmepriv->wfd_probe_resp_ie) { + pmlmepriv->wfd_probe_resp_ie_len = 0; + kfree(pmlmepriv->wfd_probe_resp_ie); + pmlmepriv->wfd_probe_resp_ie = NULL; + } + + pmlmepriv->wfd_probe_resp_ie = + kmalloc(wfd_ielen, GFP_KERNEL); + if (pmlmepriv->wfd_probe_resp_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_resp_ie, + &pmlmepriv->wfd_probe_resp_ie_len); + } +#endif /* CONFIG_8723AU_P2P */ + } + + return ret; +} + +static int rtw_cfg80211_set_assoc_resp_wpsp2pie(struct net_device *net, + char *buf, int len) +{ + int ret = 0; + struct rtw_adapter *padapter = netdev_priv(net); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + DBG_8723A("%s, ielen =%d\n", __func__, len); + + if (len > 0) { + if (pmlmepriv->wps_assoc_resp_ie) { + pmlmepriv->wps_assoc_resp_ie_len = 0; + kfree(pmlmepriv->wps_assoc_resp_ie); + pmlmepriv->wps_assoc_resp_ie = NULL; + } + + pmlmepriv->wps_assoc_resp_ie = kmalloc(len, GFP_KERNEL); + if (pmlmepriv->wps_assoc_resp_ie == NULL) { + DBG_8723A("%s()-%d: kmalloc() ERROR!\n", + __func__, __LINE__); + return -EINVAL; + + } + memcpy(pmlmepriv->wps_assoc_resp_ie, buf, len); + pmlmepriv->wps_assoc_resp_ie_len = len; + } + + return ret; +} + +int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, + int type) +{ + int ret = 0; + uint wps_ielen = 0; + u32 p2p_ielen = 0; + +#ifdef CONFIG_DEBUG_CFG80211 + DBG_8723A("%s, ielen =%d\n", __func__, len); +#endif + + if ((rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen) && (wps_ielen > 0)) +#ifdef CONFIG_8723AU_P2P + || (rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen) && (p2p_ielen > 0)) +#endif + ) { + if (net) { + switch (type) { + case 0x1: /* BEACON */ + ret = + rtw_cfg80211_set_beacon_wpsp2pie(net, buf, + len); + break; + case 0x2: /* PROBE_RESP */ + ret = + rtw_cfg80211_set_probe_resp_wpsp2pie(net, + buf, + len); + break; + case 0x4: /* ASSOC_RESP */ + ret = + rtw_cfg80211_set_assoc_resp_wpsp2pie(net, + buf, + len); + break; + } + } + } + + return ret; + +} + +static struct cfg80211_ops rtw_cfg80211_ops = { + .change_virtual_intf = cfg80211_rtw_change_iface, + .add_key = cfg80211_rtw_add_key, + .get_key = cfg80211_rtw_get_key, + .del_key = cfg80211_rtw_del_key, + .set_default_key = cfg80211_rtw_set_default_key, + .get_station = cfg80211_rtw_get_station, + .scan = cfg80211_rtw_scan, + .set_wiphy_params = cfg80211_rtw_set_wiphy_params, + .connect = cfg80211_rtw_connect, + .disconnect = cfg80211_rtw_disconnect, + .join_ibss = cfg80211_rtw_join_ibss, + .leave_ibss = cfg80211_rtw_leave_ibss, + .set_tx_power = cfg80211_rtw_set_txpower, + .get_tx_power = cfg80211_rtw_get_txpower, + .set_power_mgmt = cfg80211_rtw_set_power_mgmt, + .set_pmksa = cfg80211_rtw_set_pmksa, + .del_pmksa = cfg80211_rtw_del_pmksa, + .flush_pmksa = cfg80211_rtw_flush_pmksa, + +#ifdef CONFIG_8723AU_AP_MODE + .add_virtual_intf = cfg80211_rtw_add_virtual_intf, + .del_virtual_intf = cfg80211_rtw_del_virtual_intf, + + .start_ap = cfg80211_rtw_start_ap, + .change_beacon = cfg80211_rtw_change_beacon, + .stop_ap = cfg80211_rtw_stop_ap, + + .add_station = cfg80211_rtw_add_station, + .del_station = cfg80211_rtw_del_station, + .change_station = cfg80211_rtw_change_station, + .dump_station = cfg80211_rtw_dump_station, + .change_bss = cfg80211_rtw_change_bss, +#endif /* CONFIG_8723AU_AP_MODE */ + +#ifdef CONFIG_8723AU_P2P + .remain_on_channel = cfg80211_rtw_remain_on_channel, + .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel, +#endif + + .mgmt_tx = cfg80211_rtw_mgmt_tx, + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, +}; + +static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, + enum ieee80211_band band, u8 rf_type) +{ + +#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */ +#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */ + + ht_cap->ht_supported = true; + + ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + + /* + *Maximum length of AMPDU that the STA can receive. + *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) + */ + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + + /*Minimum MPDU start spacing , */ + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + /* + *hw->wiphy->bands[IEEE80211_BAND_2GHZ] + *base on ant_num + *rx_mask: RX mask + *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7 + *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15 + *if rx_ant >= 3 rx_mask[2]= 0xff; + *if BW_40 rx_mask[4]= 0x01; + *highest supported RX rate + */ + if (rf_type == RF_1T1R) { + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0x00; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7; + } else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) { + ht_cap->mcs.rx_mask[0] = 0xFF; + ht_cap->mcs.rx_mask[1] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + + ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15; + } else { + DBG_8723A("%s, error rf_type =%d\n", __func__, rf_type); + } + +} + +void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter) +{ + u8 rf_type; + struct ieee80211_supported_band *bands; + struct wireless_dev *pwdev = padapter->rtw_wdev; + struct wiphy *wiphy = pwdev->wiphy; + + rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + + DBG_8723A("%s:rf_type =%d\n", __func__, rf_type); + + /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ + { + bands = wiphy->bands[IEEE80211_BAND_2GHZ]; + if (bands) + rtw_cfg80211_init_ht_capab(&bands->ht_cap, + IEEE80211_BAND_2GHZ, + rf_type); + } + + /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ + { + bands = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (bands) + rtw_cfg80211_init_ht_capab(&bands->ht_cap, + IEEE80211_BAND_5GHZ, + rf_type); + } +} + +static void rtw_cfg80211_preinit_wiphy(struct rtw_adapter *padapter, + struct wiphy *wiphy) +{ + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS; + + wiphy->max_remain_on_channel_duration = + RTW_MAX_REMAIN_ON_CHANNEL_DURATION; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | +#ifdef CONFIG_8723AU_AP_MODE + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | +#endif +#if defined(CONFIG_8723AU_P2P) + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | +#endif + 0; + +#ifdef CONFIG_8723AU_AP_MODE + wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes; +#endif /* CONFIG_8723AU_AP_MODE */ + + wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); + + /* + wiphy->iface_combinations = &rtw_combinations; + wiphy->n_iface_combinations = 1; + */ + + wiphy->cipher_suites = rtw_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites); + + /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */ + wiphy->bands[IEEE80211_BAND_2GHZ] = + rtw_spt_band_alloc(IEEE80211_BAND_2GHZ); + /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */ + wiphy->bands[IEEE80211_BAND_5GHZ] = + rtw_spt_band_alloc(IEEE80211_BAND_5GHZ); + + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; + + if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; + else + wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; +} + +int rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev) +{ + int ret = 0; + struct wiphy *wiphy; + struct wireless_dev *wdev; + struct rtw_wdev_priv *pwdev_priv; + struct net_device *pnetdev = padapter->pnetdev; + + DBG_8723A("%s(padapter =%p)\n", __func__, padapter); + + /* wiphy */ + wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wdev_priv)); + if (!wiphy) { + DBG_8723A("Couldn't allocate wiphy device\n"); + ret = -ENOMEM; + goto exit; + } + set_wiphy_dev(wiphy, dev); + rtw_cfg80211_preinit_wiphy(padapter, wiphy); + + ret = wiphy_register(wiphy); + if (ret < 0) { + DBG_8723A("Couldn't register wiphy device\n"); + goto free_wiphy; + } + + /* wdev */ + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + DBG_8723A("Couldn't allocate wireless device\n"); + ret = -ENOMEM; + goto unregister_wiphy; + } + wdev->wiphy = wiphy; + wdev->netdev = pnetdev; + /* wdev->iftype = NL80211_IFTYPE_STATION; */ + /* for rtw_setopmode_cmd23a() in cfg80211_rtw_change_iface() */ + wdev->iftype = NL80211_IFTYPE_MONITOR; + padapter->rtw_wdev = wdev; + pnetdev->ieee80211_ptr = wdev; + + /* init pwdev_priv */ + pwdev_priv = wdev_to_priv(wdev); + pwdev_priv->rtw_wdev = wdev; + pwdev_priv->pmon_ndev = NULL; + pwdev_priv->ifname_mon[0] = '\0'; + pwdev_priv->padapter = padapter; + pwdev_priv->scan_request = NULL; + spin_lock_init(&pwdev_priv->scan_req_lock); + + pwdev_priv->p2p_enabled = false; + pwdev_priv->provdisc_req_issued = false; + rtw_wdev_invit_info_init(&pwdev_priv->invit_info); + + if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) + pwdev_priv->power_mgmt = true; + else + pwdev_priv->power_mgmt = false; + + return ret; +unregister_wiphy: + wiphy_unregister(wiphy); +free_wiphy: + wiphy_free(wiphy); +exit: + return ret; +} + +void rtw_wdev_free(struct wireless_dev *wdev) +{ + struct rtw_wdev_priv *pwdev_priv; + + DBG_8723A("%s(wdev =%p)\n", __func__, wdev); + + if (!wdev) + return; + + pwdev_priv = wdev_to_priv(wdev); + + kfree(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]); + kfree(wdev->wiphy->bands[IEEE80211_BAND_5GHZ]); + + wiphy_free(wdev->wiphy); + + kfree(wdev); +} + +void rtw_wdev_unregister(struct wireless_dev *wdev) +{ + struct rtw_wdev_priv *pwdev_priv; + + DBG_8723A("%s(wdev =%p)\n", __func__, wdev); + + if (!wdev) + return; + + pwdev_priv = wdev_to_priv(wdev); + + rtw_cfg80211_indicate_scan_done(pwdev_priv, true); + + if (pwdev_priv->pmon_ndev) { + DBG_8723A("%s, unregister monitor interface\n", __func__); + unregister_netdev(pwdev_priv->pmon_ndev); + } + + wiphy_unregister(wdev->wiphy); +} diff --git a/drivers/staging/rtl8723au/os_dep/mlme_linux.c b/drivers/staging/rtl8723au/os_dep/mlme_linux.c new file mode 100644 index 000000000000..b30d4d37556a --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/mlme_linux.c @@ -0,0 +1,187 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#define _MLME_OSDEP_C_ + +#include +#include +#include +#include + +void rtw_os_indicate_connect23a(struct rtw_adapter *adapter) +{ + rtw_cfg80211_indicate_connect(adapter); + + netif_carrier_on(adapter->pnetdev); + + if (adapter->pid[2] != 0) + rtw_signal_process(adapter->pid[2], SIGALRM); +} + +void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted) +{ + rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev), + aborted); +} + +static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE]; + +void rtw_reset_securitypriv23a(struct rtw_adapter *adapter) +{ + u8 backupPMKIDIndex = 0; + u8 backupTKIPCountermeasure = 0x00; + unsigned long backupTKIPcountermeasure_time = 0; + + if (adapter->securitypriv.dot11AuthAlgrthm == + dot11AuthAlgrthm_8021X) { /* 802.1x */ + /* We have to backup the PMK information for WiFi PMK + * Caching test item. + * Backup the btkip_countermeasure information. + * When the countermeasure is trigger, the driver have to + * disconnect with AP for 60 seconds. + */ + memset(&backupPMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * + NUM_PMKID_CACHE); + + memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], + sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + backupPMKIDIndex = adapter->securitypriv.PMKIDIndex; + backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure; + backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time; + + memset((unsigned char *)&adapter->securitypriv, 0, + sizeof (struct security_priv)); + /* Restore the PMK information to securitypriv structure + * for the following connection. + */ + memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], + sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); + adapter->securitypriv.PMKIDIndex = backupPMKIDIndex; + adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure; + adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time; + + adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; + adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; + } else { /* reset values in securitypriv */ + struct security_priv *psec_priv = &adapter->securitypriv; + + /* open system */ + psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; + psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + psec_priv->dot11PrivacyKeyIndex = 0; + + psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; + psec_priv->dot118021XGrpKeyid = 1; + + psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; + psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; + } +} + +void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter) +{ + /* Do it first for tx broadcast pkt after disconnection issue! */ + netif_carrier_off(adapter->pnetdev); + + rtw_cfg80211_indicate_disconnect(adapter); + + rtw_reset_securitypriv23a(adapter); +} + +void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie) +{ + uint len; + u8 *buff, *p, i; + union iwreq_data wrqu; + + RT_TRACE(_module_mlme_osdep_c_, _drv_info_, + ("+rtw_report_sec_ie23a, authmode =%d\n", authmode)); + + buff = NULL; + if (authmode == _WPA_IE_ID_) { + RT_TRACE(_module_mlme_osdep_c_, _drv_info_, + ("rtw_report_sec_ie23a, authmode =%d\n", authmode)); + + buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!buff) + return; + p = buff; + + p += sprintf(p, "ASSOCINFO(ReqIEs ="); + + len = sec_ie[1]+2; + len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; + + for (i = 0; i < len; i++) + p += sprintf(p, "%02x", sec_ie[i]); + + p += sprintf(p, ")"); + + memset(&wrqu, 0, sizeof(wrqu)); + + wrqu.data.length = p-buff; + + wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? + wrqu.data.length : IW_CUSTOM_MAX; + + kfree(buff); + } +} + +#ifdef CONFIG_8723AU_AP_MODE +void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, + struct sta_info *psta) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + union iwreq_data wrqu; + + if (psta == NULL) + return; + + if (psta->aid > NUM_STA) + return; + + if (pstapriv->sta_aid[psta->aid - 1] != psta) + return; + + wrqu.addr.sa_family = ARPHRD_ETHER; + + memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); + + DBG_8723A("+rtw_indicate_sta_assoc_event23a\n"); +} + +void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, + struct sta_info *psta) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + union iwreq_data wrqu; + + if (psta == NULL) + return; + + if (psta->aid > NUM_STA) + return; + + if (pstapriv->sta_aid[psta->aid - 1] != psta) + return; + + wrqu.addr.sa_family = ARPHRD_ETHER; + + memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); + + DBG_8723A("+rtw_indicate_sta_disassoc_event23a\n"); +} +#endif diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c new file mode 100644 index 000000000000..57eca7a45672 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c @@ -0,0 +1,970 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _OS_INTFS_C_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); +MODULE_AUTHOR("Realtek Semiconductor Corp."); +MODULE_AUTHOR("Larry Finger "); +MODULE_AUTHOR("Jes Sorensen "); +MODULE_VERSION(DRIVERVERSION); +MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); + +/* module param defaults */ +static int rtw_chip_version = 0x00; +static int rtw_rfintfs = HWPI; +static int rtw_debug = 1; + +static int rtw_channel = 1;/* ad-hoc support requirement */ +static int rtw_wireless_mode = WIRELESS_11BG_24N; +static int rtw_vrtl_carrier_sense = AUTO_VCS; +static int rtw_vcs_type = RTS_CTS;/* */ +static int rtw_rts_thresh = 2347;/* */ +static int rtw_frag_thresh = 2346;/* */ +static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */ +static int rtw_scan_mode = 1;/* active, passive */ +static int rtw_adhoc_tx_pwr = 1; +static int rtw_soft_ap; +static int rtw_power_mgnt = 1; +static int rtw_ips_mode = IPS_NORMAL; + +static int rtw_smart_ps = 2; + +module_param(rtw_ips_mode, int, 0644); +MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode"); + +static int rtw_long_retry_lmt = 7; +static int rtw_short_retry_lmt = 7; +static int rtw_busy_thresh = 40; +static int rtw_ack_policy = NORMAL_ACK; + +static int rtw_acm_method;/* 0:By SW 1:By HW. */ + +static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */ +static int rtw_uapsd_enable; + +int rtw_ht_enable23A = 1; +/* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */ +int rtw_cbw40_enable23A = 3; +int rtw_ampdu_enable23A = 1;/* for enable tx_ampdu */ +/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable + * 2.4GHZ for IOT issue with bufflao's AP at 5GHZ + */ +static int rtw_rx_stbc = 1; +static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */ + +/* Use 2 path Tx to transmit MCS0~7 and legacy mode */ +static int rtw_lowrate_two_xmit = 1; + +/* int rf_config = RF_1T2R; 1T2R */ +static int rtw_rf_config = RF_819X_MAX_TYPE; /* auto */ +static int rtw_low_power; +static int rtw_wifi_spec; +static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX; + +#ifdef CONFIG_8723AU_BT_COEXIST +static int rtw_btcoex_enable = 1; +static int rtw_bt_iso = 2;/* 0:Low, 1:High, 2:From Efuse */ +/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */ +static int rtw_bt_sco = 3; +/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ +static int rtw_bt_ampdu = 1 ; +#endif + +/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */ +static int rtw_AcceptAddbaReq = true; + +static int rtw_antdiv_cfg = 2; /* 0:OFF , 1:ON, 2:decide by Efuse config */ +static int rtw_antdiv_type; /* 0:decide by efuse */ + +static int rtw_enusbss;/* 0:disable, 1:enable */ + +static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */ + +static int rtw_hwpwrp_detect; /* HW power ping detect 0:disable , 1:enable */ + +static int rtw_hw_wps_pbc = 1; + +static int rtw_80211d; + +static int rtw_regulatory_id = 0xff;/* Regulatory tab id, 0xff = follow efuse's setting */ + +module_param(rtw_regulatory_id, int, 0644); + +static char *ifname = "wlan%d"; +module_param(ifname, charp, 0644); +MODULE_PARM_DESC(ifname, "The default name to allocate for first interface"); + +static char *if2name = "wlan%d"; +module_param(if2name, charp, 0644); +MODULE_PARM_DESC(if2name, "The default name to allocate for second interface"); + +module_param(rtw_channel_plan, int, 0644); +module_param(rtw_chip_version, int, 0644); +module_param(rtw_rfintfs, int, 0644); +module_param(rtw_channel, int, 0644); +module_param(rtw_wmm_enable, int, 0644); +module_param(rtw_vrtl_carrier_sense, int, 0644); +module_param(rtw_vcs_type, int, 0644); +module_param(rtw_busy_thresh, int, 0644); +module_param(rtw_ht_enable23A, int, 0644); +module_param(rtw_cbw40_enable23A, int, 0644); +module_param(rtw_ampdu_enable23A, int, 0644); +module_param(rtw_rx_stbc, int, 0644); +module_param(rtw_ampdu_amsdu, int, 0644); + +module_param(rtw_lowrate_two_xmit, int, 0644); + +module_param(rtw_rf_config, int, 0644); +module_param(rtw_power_mgnt, int, 0644); +module_param(rtw_smart_ps, int, 0644); +module_param(rtw_low_power, int, 0644); +module_param(rtw_wifi_spec, int, 0644); + +module_param(rtw_antdiv_cfg, int, 0644); + +module_param(rtw_enusbss, int, 0644); +module_param(rtw_hwpdn_mode, int, 0644); +module_param(rtw_hwpwrp_detect, int, 0644); + +module_param(rtw_hw_wps_pbc, int, 0644); + +static uint rtw_max_roaming_times = 2; +module_param(rtw_max_roaming_times, uint, 0644); +MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try"); + +module_param(rtw_80211d, int, 0644); +MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism"); + +#ifdef CONFIG_8723AU_BT_COEXIST +module_param(rtw_btcoex_enable, int, 0644); +MODULE_PARM_DESC(rtw_btcoex_enable, "Enable BT co-existence mechanism"); +#endif + +static uint rtw_notch_filter; +module_param(rtw_notch_filter, uint, 0644); +MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P"); +module_param_named(debug, rtw_debug, int, 0444); +MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)"); + +static int netdev_close(struct net_device *pnetdev); + +static uint loadparam(struct rtw_adapter *padapter, struct net_device *pnetdev) +{ + struct registry_priv *registry_par = &padapter->registrypriv; + uint status = _SUCCESS; + + GlobalDebugLevel23A = rtw_debug; + registry_par->chip_version = (u8)rtw_chip_version; + registry_par->rfintfs = (u8)rtw_rfintfs; + memcpy(registry_par->ssid.ssid, "ANY", 3); + registry_par->ssid.ssid_len = 3; + registry_par->channel = (u8)rtw_channel; + registry_par->wireless_mode = (u8)rtw_wireless_mode; + registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense; + registry_par->vcs_type = (u8)rtw_vcs_type; + registry_par->rts_thresh = (u16)rtw_rts_thresh; + registry_par->frag_thresh = (u16)rtw_frag_thresh; + registry_par->preamble = (u8)rtw_preamble; + registry_par->scan_mode = (u8)rtw_scan_mode; + registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr; + registry_par->soft_ap = (u8)rtw_soft_ap; + registry_par->smart_ps = (u8)rtw_smart_ps; + registry_par->power_mgnt = (u8)rtw_power_mgnt; + registry_par->ips_mode = (u8)rtw_ips_mode; + registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt; + registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt; + registry_par->busy_thresh = (u16)rtw_busy_thresh; + registry_par->ack_policy = (u8)rtw_ack_policy; + registry_par->acm_method = (u8)rtw_acm_method; + /* UAPSD */ + registry_par->wmm_enable = (u8)rtw_wmm_enable; + registry_par->uapsd_enable = (u8)rtw_uapsd_enable; + registry_par->ht_enable = (u8)rtw_ht_enable23A; + registry_par->cbw40_enable = (u8)rtw_cbw40_enable23A; + registry_par->ampdu_enable = (u8)rtw_ampdu_enable23A; + registry_par->rx_stbc = (u8)rtw_rx_stbc; + registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; + registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; + registry_par->rf_config = (u8)rtw_rf_config; + registry_par->low_power = (u8)rtw_low_power; + registry_par->wifi_spec = (u8)rtw_wifi_spec; + registry_par->channel_plan = (u8)rtw_channel_plan; +#ifdef CONFIG_8723AU_BT_COEXIST + registry_par->btcoex = (u8)rtw_btcoex_enable; + registry_par->bt_iso = (u8)rtw_bt_iso; + registry_par->bt_sco = (u8)rtw_bt_sco; + registry_par->bt_ampdu = (u8)rtw_bt_ampdu; +#endif + registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq; + registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg; + registry_par->antdiv_type = (u8)rtw_antdiv_type; + + /* 0:disable, 1:enable, 2:by EFUSE config */ + registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode; + /* 0:disable, 1:enable */ + registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect; + registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc; + registry_par->max_roaming_times = (u8)rtw_max_roaming_times; + registry_par->enable80211d = (u8)rtw_80211d; + snprintf(registry_par->ifname, 16, "%s", ifname); + snprintf(registry_par->if2name, 16, "%s", if2name); + registry_par->notch_filter = (u8)rtw_notch_filter; + registry_par->regulatory_tid = (u8)rtw_regulatory_id; + return status; +} + +static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) +{ + struct rtw_adapter *padapter = netdev_priv(pnetdev); + struct sockaddr *addr = p; + + if (!padapter->bup) + ether_addr_copy(padapter->eeprompriv.mac_addr, addr->sa_data); + return 0; +} + +static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) +{ + struct rtw_adapter *padapter = netdev_priv(pnetdev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct recv_priv *precvpriv = &padapter->recvpriv; + + padapter->stats.tx_packets = pxmitpriv->tx_pkts; + padapter->stats.rx_packets = precvpriv->rx_pkts; + padapter->stats.tx_dropped = pxmitpriv->tx_drop; + padapter->stats.rx_dropped = precvpriv->rx_drop; + padapter->stats.tx_bytes = pxmitpriv->tx_bytes; + padapter->stats.rx_bytes = precvpriv->rx_bytes; + + return &padapter->stats; +} + +/* + * AC to queue mapping + * + * AC_VO -> queue 0 + * AC_VI -> queue 1 + * AC_BE -> queue 2 + * AC_BK -> queue 3 + */ +static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; + +/* Given a data frame determine the 802.1p/1d tag to use. */ +static unsigned int rtw_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp; + + /* skb->priority values from 256->263 are magic values to + * directly indicate a specific 802.1d priority. This is used + * to allow 802.1d priority to be passed directly in from VLAN + * tags, etc. + */ + 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; + default: + return 0; + } + return dscp >> 5; +} + +static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, + select_queue_fallback_t fallback) +{ + struct rtw_adapter *padapter = netdev_priv(dev); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + skb->priority = rtw_classify8021d(skb); + + if (pmlmepriv->acm_mask != 0) + skb->priority = qos_acm23a(pmlmepriv->acm_mask, skb->priority); + return rtw_1d_to_queue[skb->priority]; +} + +u16 rtw_recv_select_queue23a(struct sk_buff *skb) +{ + struct iphdr *piphdr; + unsigned int dscp; + u16 eth_type; + u32 priority; + u8 *pdata = skb->data; + + memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); + switch (eth_type) { + case htons(ETH_P_IP): + piphdr = (struct iphdr *)(pdata + ETH_HLEN); + dscp = piphdr->tos & 0xfc; + priority = dscp >> 5; + break; + default: + priority = 0; + } + return rtw_1d_to_queue[priority]; +} + +static const struct net_device_ops rtw_netdev_ops = { + .ndo_open = netdev_open23a, + .ndo_stop = netdev_close, + .ndo_start_xmit = rtw_xmit23a_entry23a, + .ndo_select_queue = rtw_select_queue, + .ndo_set_mac_address = rtw_net_set_mac_address, + .ndo_get_stats = rtw_net_get_stats, +}; + +int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname) +{ + if (dev_alloc_name(pnetdev, ifname) < 0) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("dev_alloc_name, fail!\n")); + } + netif_carrier_off(pnetdev); + return 0; +} + +static const struct device_type wlan_type = { + .name = "wlan", +}; + +struct net_device *rtw_init_netdev23a(struct rtw_adapter *old_padapter) +{ + struct rtw_adapter *padapter; + struct net_device *pnetdev; + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n")); + + pnetdev = alloc_etherdev_mq(sizeof(struct rtw_adapter), 4); + if (!pnetdev) + return NULL; + + pnetdev->dev.type = &wlan_type; + padapter = netdev_priv(pnetdev); + padapter->pnetdev = pnetdev; + + DBG_8723A("register rtw_netdev_ops to netdev_ops\n"); + pnetdev->netdev_ops = &rtw_netdev_ops; + + pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */ + + /* step 2. */ + loadparam(padapter, pnetdev); + return pnetdev; +} + +u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter) +{ + u32 _status = _SUCCESS; + + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("+rtw_start_drv_threads23a\n")); + padapter->cmdThread = kthread_run(rtw_cmd_thread23a, padapter, + "RTW_CMD_THREAD"); + if (IS_ERR(padapter->cmdThread)) { + _status = _FAIL; + } else { + /* wait for cmd_thread to run */ + down(&padapter->cmdpriv.terminate_cmdthread_sema); + } + rtw_hal_start_thread23a(padapter); + return _status; +} + +void rtw_stop_drv_threads23a(struct rtw_adapter *padapter) +{ + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads23a\n")); + + /* Below is to termindate rtw_cmd_thread23a & event_thread... */ + up(&padapter->cmdpriv.cmd_queue_sema); + if (padapter->cmdThread) + down(&padapter->cmdpriv.terminate_cmdthread_sema); + rtw_hal_stop_thread23a(padapter); +} + +static u8 rtw_init_default_value(struct rtw_adapter *padapter) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 ret = _SUCCESS; + + /* xmit_priv */ + pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; + pxmitpriv->vcs = pregistrypriv->vcs_type; + pxmitpriv->vcs_type = pregistrypriv->vcs_type; + /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */ + pxmitpriv->frag_len = pregistrypriv->frag_thresh; + + /* mlme_priv */ + pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ + pmlmepriv->scan_mode = SCAN_ACTIVE; + + /* ht_priv */ + pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */ + + /* security_priv */ + psecuritypriv->binstallGrpkey = _FAIL; + + /* open system */ + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; + psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + + psecuritypriv->dot11PrivacyKeyIndex = 0; + + psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; + psecuritypriv->dot118021XGrpKeyid = 1; + + psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; + psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled; + + /* registry_priv */ + rtw_init_registrypriv_dev_network23a(padapter); + rtw_update_registrypriv_dev_network23a(padapter); + + /* hal_priv */ + rtw_hal_def_value_init23a(padapter); + + /* misc. */ + padapter->bReadPortCancel = false; + padapter->bWritePortCancel = false; + padapter->bRxRSSIDisplay = 0; + padapter->bNotifyChannelChange = 0; +#ifdef CONFIG_8723AU_P2P + padapter->bShowGetP2PState = 1; +#endif + return ret; +} + +u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; + u8 ret8 = _SUCCESS; + + /* hal_priv */ + rtw_hal_def_value_init23a(padapter); + padapter->bReadPortCancel = false; + padapter->bWritePortCancel = false; + padapter->bRxRSSIDisplay = 0; + pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ + + padapter->xmitpriv.tx_pkts = 0; + padapter->recvpriv.rx_pkts = 0; + + pmlmepriv->LinkDetectInfo.bBusyTraffic = false; + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING); + + rtw_hal_sreset_reset23a_value23a(padapter); + pwrctrlpriv->pwr_state_check_cnts = 0; + + /* mlmeextpriv */ + padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE; + + rtw_set_signal_stat_timer(&padapter->recvpriv); + return ret8; +} + +u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter) +{ + u8 ret8 = _SUCCESS; + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw23a\n")); + + if ((rtw_init_cmd_priv23a(&padapter->cmdpriv)) == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't init cmd_priv\n")); + ret8 = _FAIL; + goto exit; + } + + padapter->cmdpriv.padapter = padapter; + + if (rtw_init_evt_priv23a(&padapter->evtpriv) == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't init evt_priv\n")); + ret8 = _FAIL; + goto exit; + } + + if (rtw_init_mlme_priv23a(padapter) == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't init mlme_priv\n")); + ret8 = _FAIL; + goto exit; + } + +#ifdef CONFIG_8723AU_P2P + rtw_init_wifidirect_timers23a(padapter); + init_wifidirect_info23a(padapter, P2P_ROLE_DISABLE); + reset_global_wifidirect_info23a(padapter); + rtw_init_cfg80211_wifidirect_info(padapter); +#ifdef CONFIG_8723AU_P2P + if (rtw_init_wifi_display_info(padapter) == _FAIL) + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't init init_wifi_display_info\n")); +#endif +#endif /* CONFIG_8723AU_P2P */ + + if (init_mlme_ext_priv23a(padapter) == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't init mlme_ext_priv\n")); + ret8 = _FAIL; + goto exit; + } + + if (_rtw_init_xmit_priv23a(&padapter->xmitpriv, padapter) == _FAIL) { + DBG_8723A("Can't _rtw_init_xmit_priv23a\n"); + ret8 = _FAIL; + goto exit; + } + + if (_rtw_init_recv_priv23a(&padapter->recvpriv, padapter) == _FAIL) { + DBG_8723A("Can't _rtw_init_recv_priv23a\n"); + ret8 = _FAIL; + goto exit; + } + + if (_rtw_init_sta_priv23a(&padapter->stapriv) == _FAIL) { + DBG_8723A("Can't _rtw_init_sta_priv23a\n"); + ret8 = _FAIL; + goto exit; + } + + padapter->stapriv.padapter = padapter; + padapter->setband = GHZ24_50; + rtw_init_bcmc_stainfo23a(padapter); + + rtw_init_pwrctrl_priv23a(padapter); + + ret8 = rtw_init_default_value(padapter); + + rtw_hal_dm_init23a(padapter); + rtw_hal_sw_led_init23a(padapter); + + rtw_hal_sreset_init23a(padapter); + +exit: + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw23a\n")); + return ret8; +} + +void rtw_cancel_all_timer23a(struct rtw_adapter *padapter) +{ + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer23a\n")); + + del_timer_sync(&padapter->mlmepriv.assoc_timer); + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("rtw_cancel_all_timer23a:cancel association timer complete!\n")); + + del_timer_sync(&padapter->mlmepriv.scan_to_timer); + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("rtw_cancel_all_timer23a:cancel scan_to_timer!\n")); + + del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer); + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("rtw_cancel_all_timer23a:cancel dynamic_chk_timer!\n")); + + /* cancel sw led timer */ + rtw_hal_sw_led_deinit23a(padapter); + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("rtw_cancel_all_timer23a:cancel DeInitSwLeds!\n")); + + del_timer_sync(&padapter->pwrctrlpriv.pwr_state_check_timer); + +#ifdef CONFIG_8723AU_P2P + del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); +#endif /* CONFIG_8723AU_P2P */ + + del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer); + rtw_clear_scan_deny(padapter); + RT_TRACE(_module_os_intfs_c_, _drv_info_, + ("rtw_cancel_all_timer23a:cancel set_scan_deny_timer!\n")); + + del_timer_sync(&padapter->recvpriv.signal_stat_timer); + /* cancel dm timer */ + rtw_hal_dm_deinit23a(padapter); +} + +u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter) +{ +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo; +#endif + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw23a")); + + /* we can call rtw_p2p_enable23a here, but: + * 1. rtw_p2p_enable23a may have IO operation + * 2. rtw_p2p_enable23a is bundled with wext interface + */ +#ifdef CONFIG_8723AU_P2P + pwdinfo = &padapter->wdinfo; + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + del_timer_sync(&pwdinfo->find_phase_timer); + del_timer_sync(&pwdinfo->restore_p2p_state_timer); + del_timer_sync(&pwdinfo->pre_tx_scan_timer); + rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); + } +#endif + + free_mlme_ext_priv23a(&padapter->mlmeextpriv); + + rtw_free_cmd_priv23a(&padapter->cmdpriv); + + rtw_free_evt_priv23a(&padapter->evtpriv); + + rtw_free_mlme_priv23a(&padapter->mlmepriv); + + _rtw_free_xmit_priv23a(&padapter->xmitpriv); + + _rtw_free_sta_priv23a(&padapter->stapriv);/* will free bcmc_stainfo here */ + + _rtw_free_recv_priv23a(&padapter->recvpriv); + + rtw_free_pwrctrl_priv(padapter); + + rtw_hal_free_data23a(padapter); + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw23a\n")); + + /* free the old_pnetdev */ + if (padapter->rereg_nd_name_priv.old_pnetdev) { + free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); + padapter->rereg_nd_name_priv.old_pnetdev = NULL; + } + + /* clear pbuddy_adapter to avoid access wrong pointer. */ + if (padapter->pbuddy_adapter != NULL) + padapter->pbuddy_adapter->pbuddy_adapter = NULL; + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw23a\n")); + return _SUCCESS; +} + +static int _rtw_drv_register_netdev(struct rtw_adapter *padapter, char *name) +{ + struct net_device *pnetdev = padapter->pnetdev; + int ret = _SUCCESS; + + /* alloc netdev name */ + rtw_init_netdev23a_name23a(pnetdev, name); + + ether_addr_copy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr); + + /* Tell the network stack we exist */ + if (register_netdev(pnetdev)) { + DBG_8723A(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev)); + ret = _FAIL; + goto error_register_netdev; + } + DBG_8723A("%s, MAC Address (if%d) = " MAC_FMT "\n", __func__, + (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr)); + return ret; + +error_register_netdev: + + if (padapter->iface_id > IFACE_ID0) { + rtw_free_drv_sw23a(padapter); + + free_netdev(pnetdev); + } + return ret; +} + +int rtw_drv_register_netdev(struct rtw_adapter *if1) +{ + struct dvobj_priv *dvobj = if1->dvobj; + int i, status = _SUCCESS; + + if (dvobj->iface_nums < IFACE_ID_MAX) { + for (i = 0; i < dvobj->iface_nums; i++) { + struct rtw_adapter *padapter = dvobj->padapters[i]; + + if (padapter) { + char *name; + + if (padapter->iface_id == IFACE_ID0) + name = if1->registrypriv.ifname; + else if (padapter->iface_id == IFACE_ID1) + name = if1->registrypriv.if2name; + else + name = "wlan%d"; + status = _rtw_drv_register_netdev(padapter, + name); + if (status != _SUCCESS) + break; + } + } + } + return status; +} + +int netdev_open23a(struct net_device *pnetdev) +{ + struct rtw_adapter *padapter = netdev_priv(pnetdev); + struct pwrctrl_priv *pwrctrlpriv; + int ret = 0; + uint status; + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - dev_open\n")); + DBG_8723A("+871x_drv - drv_open, bup =%d\n", padapter->bup); + + mutex_lock(&adapter_to_dvobj(padapter)->hw_init_mutex); + + pwrctrlpriv = &padapter->pwrctrlpriv; + if (pwrctrlpriv->ps_flag) { + padapter->net_closed = false; + goto netdev_open23a_normal_process; + } + + if (!padapter->bup) { + padapter->bDriverStopped = false; + padapter->bSurpriseRemoved = false; + padapter->bCardDisableWOHSM = false; + + status = rtw_hal_init23a(padapter); + if (status == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("rtl871x_hal_init(): Can't init h/w!\n")); + goto netdev_open23a_error; + } + + DBG_8723A("MAC Address = "MAC_FMT"\n", + MAC_ARG(pnetdev->dev_addr)); + + status = rtw_start_drv_threads23a(padapter); + if (status == _FAIL) { + DBG_8723A("Initialize driver software resource Failed!\n"); + goto netdev_open23a_error; + } + + if (init_hw_mlme_ext23a(padapter) == _FAIL) { + DBG_8723A("can't init mlme_ext_priv\n"); + goto netdev_open23a_error; + } + + if (padapter->intf_start) + padapter->intf_start(padapter); + + rtw_cfg80211_init_wiphy(padapter); + + rtw_led_control(padapter, LED_CTL_NO_LINK); + + padapter->bup = true; + } + padapter->net_closed = false; + + mod_timer(&padapter->mlmepriv.dynamic_chk_timer, + jiffies + msecs_to_jiffies(2000)); + + padapter->pwrctrlpriv.bips_processing = false; + rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); + + /* netif_carrier_on(pnetdev);call this func when + rtw23a_joinbss_event_cb return success */ + if (!rtw_netif_queue_stopped(pnetdev)) + netif_tx_start_all_queues(pnetdev); + else + netif_tx_wake_all_queues(pnetdev); + +netdev_open23a_normal_process: + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - dev_open\n")); + DBG_8723A("-871x_drv - drv_open, bup =%d\n", padapter->bup); +exit: + mutex_unlock(&adapter_to_dvobj(padapter)->hw_init_mutex); + return ret; + +netdev_open23a_error: + padapter->bup = false; + + netif_carrier_off(pnetdev); + netif_tx_stop_all_queues(pnetdev); + + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("-871x_drv - dev_open, fail!\n")); + DBG_8723A("-871x_drv - drv_open fail, bup =%d\n", padapter->bup); + + ret = -1; + goto exit; +} + +static int ips_netdrv_open(struct rtw_adapter *padapter) +{ + int status = _SUCCESS; + + padapter->net_closed = false; + DBG_8723A("===> %s.........\n", __func__); + + padapter->bDriverStopped = false; + padapter->bSurpriseRemoved = false; + padapter->bCardDisableWOHSM = false; + + status = rtw_hal_init23a(padapter); + if (status == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("ips_netdrv_open(): Can't init h/w!\n")); + goto netdev_open23a_error; + } + + if (padapter->intf_start) + padapter->intf_start(padapter); + + rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); + mod_timer(&padapter->mlmepriv.dynamic_chk_timer, + jiffies + msecs_to_jiffies(5000)); + + return _SUCCESS; + +netdev_open23a_error: + /* padapter->bup = false; */ + DBG_8723A("-ips_netdrv_open - drv_open failure, bup =%d\n", + padapter->bup); + + return _FAIL; +} + +int rtw_ips_pwr_up23a(struct rtw_adapter *padapter) +{ + int result; + unsigned long start_time = jiffies; + + DBG_8723A("===> rtw_ips_pwr_up23a..............\n"); + rtw_reset_drv_sw23a(padapter); + + result = ips_netdrv_open(padapter); + + rtw_led_control(padapter, LED_CTL_NO_LINK); + + DBG_8723A("<=== rtw_ips_pwr_up23a.............. in %dms\n", + jiffies_to_msecs(jiffies - start_time)); + return result; +} + +void rtw_ips_pwr_down23a(struct rtw_adapter *padapter) +{ + unsigned long start_time = jiffies; + + DBG_8723A("===> rtw_ips_pwr_down23a...................\n"); + + padapter->bCardDisableWOHSM = true; + padapter->net_closed = true; + + rtw_led_control(padapter, LED_CTL_POWER_OFF); + + rtw_ips_dev_unload23a(padapter); + padapter->bCardDisableWOHSM = false; + DBG_8723A("<=== rtw_ips_pwr_down23a..................... in %dms\n", + jiffies_to_msecs(jiffies - start_time)); +} + +void rtw_ips_dev_unload23a(struct rtw_adapter *padapter) +{ + rtw_hal_set_hwreg23a(padapter, HW_VAR_FIFO_CLEARN_UP, NULL); + + if (padapter->intf_stop) + padapter->intf_stop(padapter); + + /* s5. */ + if (!padapter->bSurpriseRemoved) + rtw_hal_deinit23a(padapter); +} + +int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal) +{ + int status; + + if (bnormal) + status = netdev_open23a(pnetdev); + else + status = (_SUCCESS == ips_netdrv_open(netdev_priv(pnetdev))) ? + (0) : (-1); + + return status; +} + +static int netdev_close(struct net_device *pnetdev) +{ + struct rtw_adapter *padapter = netdev_priv(pnetdev); + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - drv_close\n")); + + if (padapter->pwrctrlpriv.bInternalAutoSuspend) { + if (padapter->pwrctrlpriv.rf_pwrstate == rf_off) + padapter->pwrctrlpriv.ps_flag = true; + } + padapter->net_closed = true; + + if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) { + DBG_8723A("(2)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n", + padapter->bup, + padapter->hw_init_completed); + + /* s1. */ + if (pnetdev) { + if (!rtw_netif_queue_stopped(pnetdev)) + netif_tx_stop_all_queues(pnetdev); + } + + /* s2. */ + LeaveAllPowerSaveMode23a(padapter); + rtw_disassoc_cmd23a(padapter, 500, false); + /* s2-2. indicate disconnect to os */ + rtw_indicate_disconnect23a(padapter); + /* s2-3. */ + rtw_free_assoc_resources23a(padapter, 1); + /* s2-4. */ + rtw_free_network_queue23a(padapter, true); + /* Close LED */ + rtw_led_control(padapter, LED_CTL_POWER_OFF); + } + +#ifdef CONFIG_8723AU_P2P + if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) + wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = false; + rtw_p2p_enable23a(padapter, P2P_ROLE_DISABLE); +#endif /* CONFIG_8723AU_P2P */ + + rtw_scan_abort23a(padapter); + /* set this at the end */ + padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR; + + RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - drv_close\n")); + DBG_8723A("-871x_drv - drv_close, bup =%d\n", padapter->bup); + + return 0; +} + +void rtw_ndev_destructor(struct net_device *ndev) +{ + DBG_8723A(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); + kfree(ndev->ieee80211_ptr); + free_netdev(ndev); +} diff --git a/drivers/staging/rtl8723au/os_dep/osdep_service.c b/drivers/staging/rtl8723au/os_dep/osdep_service.c new file mode 100644 index 000000000000..aeb48db0ee8c --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/osdep_service.c @@ -0,0 +1,429 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + + +#define _OSDEP_SERVICE_C_ + +#include +#include +#include +#include + +#define RT_TAG ('1178') + +/* +* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE23a +* @return: one of RTW_STATUS_CODE23a +*/ +inline int RTW_STATUS_CODE23a(int error_code) +{ + if (error_code >= 0) + return _SUCCESS; + return _FAIL; +} + +inline u8 *_rtw_vmalloc(u32 sz) +{ + u8 *pbuf; + pbuf = vmalloc(sz); + + return pbuf; +} + +inline u8 *_rtw_zvmalloc(u32 sz) +{ + u8 *pbuf; + pbuf = _rtw_vmalloc(sz); + if (pbuf != NULL) + memset(pbuf, 0, sz); + + return pbuf; +} + +inline void _rtw_vmfree(u8 *pbuf, u32 sz) +{ + vfree(pbuf); +} + +void _rtw_init_queue23a(struct rtw_queue *pqueue) +{ + INIT_LIST_HEAD(&pqueue->queue); + spin_lock_init(&pqueue->lock); +} + +u32 _rtw_queue_empty23a(struct rtw_queue *pqueue) +{ + if (list_empty(&pqueue->queue)) + return true; + else + return false; +} + +u32 rtw_get_current_time(void) +{ + return jiffies; +} + +inline u32 rtw_systime_to_ms23a(u32 systime) +{ + return systime * 1000 / HZ; +} + +inline u32 rtw_ms_to_systime23a(u32 ms) +{ + return ms * HZ / 1000; +} + +/* the input parameter start use the same unit as returned + * by rtw_get_current_time + */ +inline s32 rtw_get_passing_time_ms23a(u32 start) +{ + return rtw_systime_to_ms23a(jiffies-start); +} + +inline s32 rtw_get_time_interval_ms23a(u32 start, u32 end) +{ + return rtw_systime_to_ms23a(end-start); +} + +#define RTW_SUSPEND_LOCK_NAME "rtw_wifi" + +inline void rtw_suspend_lock_init(void) +{ +} + +inline void rtw_suspend_lock_uninit(void) +{ +} + +inline void rtw_lock_suspend(void) +{ +} + +inline void rtw_unlock_suspend(void) +{ +} + +/* Open a file with the specific @param path, @param flag, @param mode + * @param fpp the pointer of struct file pointer to get struct + * file pointer while file opening is success + * @param path the path of the file to open + * @param flag file operation flags, please refer to linux document + * @param mode please refer to linux document + * @return Linux specific error code + */ +static int openFile(struct file **fpp, char *path, int flag, int mode) +{ + struct file *fp; + + fp = filp_open(path, flag, mode); + if (IS_ERR(fp)) { + *fpp = NULL; + return PTR_ERR(fp); + } else { + *fpp = fp; + return 0; + } +} + +/* Close the file with the specific @param fp + * @param fp the pointer of struct file to close + * @return always 0 + */ +static int closeFile(struct file *fp) +{ + filp_close(fp, NULL); + return 0; +} + +static int readFile(struct file *fp, char *buf, int len) +{ + int rlen = 0, sum = 0; + + if (!fp->f_op || !fp->f_op->read) + return -EPERM; + + while (sum < len) { + rlen = fp->f_op->read(fp, buf+sum, len-sum, &fp->f_pos); + if (rlen > 0) + sum += rlen; + else if (0 != rlen) + return rlen; + else + break; + } + return sum; +} + +static int writeFile(struct file *fp, char *buf, int len) +{ + int wlen = 0, sum = 0; + + if (!fp->f_op || !fp->f_op->write) + return -EPERM; + + while (sum < len) { + wlen = fp->f_op->write(fp, buf+sum, len-sum, &fp->f_pos); + if (wlen > 0) + sum += wlen; + else if (0 != wlen) + return wlen; + else + break; + } + return sum; +} + +/* Test if the specifi @param path is a file and readable + * @param path the path of the file to test + * @return Linux specific error code + */ +static int isFileReadable(char *path) +{ + struct file *fp; + int ret = 0; + mm_segment_t oldfs; + char buf; + + fp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(fp)) { + ret = PTR_ERR(fp); + } else { + oldfs = get_fs(); + set_fs(get_ds()); + + if (1 != readFile(fp, &buf, 1)) + ret = PTR_ERR(fp); + + set_fs(oldfs); + filp_close(fp, NULL); + } + return ret; +} + +/* Open the file with @param path and retrive the file content into + * memory starting from @param buf for @param sz at most + * @param path the path of the file to open and read + * @param buf the starting address of the buffer to store file content + * @param sz how many bytes to read at most + * @return the byte we've read, or Linux specific error code + */ +static int retriveFromFile(char *path, u8 *buf, u32 sz) +{ + int ret = -1; + mm_segment_t oldfs; + struct file *fp; + + if (path && buf) { + ret = openFile(&fp, path, O_RDONLY, 0); + if (!ret) { + DBG_8723A("%s openFile path:%s fp =%p\n", + __func__, path, fp); + + oldfs = get_fs(); set_fs(get_ds()); + ret = readFile(fp, buf, sz); + set_fs(oldfs); + closeFile(fp); + + DBG_8723A("%s readFile, ret:%d\n", __func__, ret); + } else { + DBG_8723A("%s openFile path:%s Fail, ret:%d\n", + __func__, path, ret); + } + } else { + DBG_8723A("%s NULL pointer\n", __func__); + ret = -EINVAL; + } + return ret; +} + +/* Open the file with @param path and wirte @param sz byte of data starting + * from @param buf into the file + * @param path the path of the file to open and write + * @param buf the starting address of the data to write into file + * @param sz how many bytes to write at most + * @return the byte we've written, or Linux specific error code + */ +static int storeToFile(char *path, u8 *buf, u32 sz) +{ + struct file *fp; + int ret = 0; + mm_segment_t oldfs; + + if (path && buf) { + ret = openFile(&fp, path, O_CREAT|O_WRONLY, 0666); + if (!ret) { + DBG_8723A("%s openFile path:%s fp =%p\n", __func__, + path, fp); + + oldfs = get_fs(); set_fs(get_ds()); + ret = writeFile(fp, buf, sz); + set_fs(oldfs); + closeFile(fp); + + DBG_8723A("%s writeFile, ret:%d\n", __func__, ret); + } else { + DBG_8723A("%s openFile path:%s Fail, ret:%d\n", + __func__, path, ret); + } + } else { + DBG_8723A("%s NULL pointer\n", __func__); + ret = -EINVAL; + } + return ret; +} + +/* +* Test if the specifi @param path is a file and readable +* @param path the path of the file to test +* @return true or false +*/ +int rtw_is_file_readable(char *path) +{ + if (isFileReadable(path) == 0) + return true; + else + return false; +} + +/* Open the file with @param path and retrive the file content into memoryi + * starting from @param buf for @param sz at most + * @param path the path of the file to open and read + * @param buf the starting address of the buffer to store file content + * @param sz how many bytes to read at most + * @return the byte we've read + */ +int rtw_retrive_from_file(char *path, u8 *buf, u32 sz) +{ + int ret = retriveFromFile(path, buf, sz); + return ret >= 0 ? ret : 0; +} + +/* Open the file with @param path and wirte @param sz byte of + * data starting from @param buf into the file + * @param path the path of the file to open and write + * @param buf the starting address of the data to write into file + * @param sz how many bytes to write at most + * @return the byte we've written + */ +int rtw_store_to_file(char *path, u8 *buf, u32 sz) +{ + int ret = storeToFile(path, buf, sz); + return ret >= 0 ? ret : 0; +} + +u64 rtw_modular6423a(u64 x, u64 y) +{ + return do_div(x, y); +} + +u64 rtw_division6423a(u64 x, u64 y) +{ + do_div(x, y); + return x; +} + +/* rtw_cbuf_full23a - test if cbuf is full + * @cbuf: pointer of struct rtw_cbuf + * + * Returns: true if cbuf is full + */ +inline bool rtw_cbuf_full23a(struct rtw_cbuf *cbuf) +{ + return (cbuf->write == cbuf->read-1) ? true : false; +} + +/* rtw_cbuf_empty23a - test if cbuf is empty + * @cbuf: pointer of struct rtw_cbuf + * + * Returns: true if cbuf is empty + */ +inline bool rtw_cbuf_empty23a(struct rtw_cbuf *cbuf) +{ + return (cbuf->write == cbuf->read) ? true : false; +} + +/** + * rtw_cbuf_push23a - push a pointer into cbuf + * @cbuf: pointer of struct rtw_cbuf + * @buf: pointer to push in + * + * Lock free operation, be careful of the use scheme + * Returns: true push success + */ +bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf) +{ + if (rtw_cbuf_full23a(cbuf)) + return _FAIL; + + if (0) + DBG_8723A("%s on %u\n", __func__, cbuf->write); + cbuf->bufs[cbuf->write] = buf; + cbuf->write = (cbuf->write+1)%cbuf->size; + + return _SUCCESS; +} + +/** + * rtw_cbuf_pop23a - pop a pointer from cbuf + * @cbuf: pointer of struct rtw_cbuf + * + * Lock free operation, be careful of the use scheme + * Returns: pointer popped out + */ +void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf) +{ + void *buf; + if (rtw_cbuf_empty23a(cbuf)) + return NULL; + + if (0) + DBG_8723A("%s on %u\n", __func__, cbuf->read); + buf = cbuf->bufs[cbuf->read]; + cbuf->read = (cbuf->read+1)%cbuf->size; + + return buf; +} + +/** + * rtw_cbuf_alloc23a - allocte a rtw_cbuf with given size and do initialization + * @size: size of pointer + * + * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure + */ +struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size) +{ + struct rtw_cbuf *cbuf; + + cbuf = kmalloc(sizeof(*cbuf) + sizeof(void *)*size, GFP_KERNEL); + + if (cbuf) { + cbuf->write = 0; + cbuf->read = 0; + cbuf->size = size; + } + + return cbuf; +} + +/** + * rtw_cbuf_free - free the given rtw_cbuf + * @cbuf: pointer of struct rtw_cbuf to free + */ +void rtw_cbuf_free(struct rtw_cbuf *cbuf) +{ + kfree(cbuf); +} diff --git a/drivers/staging/rtl8723au/os_dep/recv_linux.c b/drivers/staging/rtl8723au/os_dep/recv_linux.c new file mode 100644 index 000000000000..84402a589f25 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/recv_linux.c @@ -0,0 +1,225 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _RECV_OSDEP_C_ + +#include +#include + +#include +#include + +#include +#include + +#include + +/* alloc os related resource in struct recv_frame */ +int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, + struct recv_frame *precvframe) +{ + int res = _SUCCESS; + + precvframe->pkt = NULL; + + return res; +} + +/* alloc os related resource in struct recv_buf */ +int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, + struct recv_buf *precvbuf) +{ + int res = _SUCCESS; + + precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); + if (precvbuf->purb == NULL) + res = _FAIL; + + precvbuf->pskb = NULL; + + return res; +} + +/* free os related resource in struct recv_buf */ +int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, + struct recv_buf *precvbuf) +{ + int ret = _SUCCESS; + + usb_free_urb(precvbuf->purb); + + if (precvbuf->pskb) + dev_kfree_skb_any(precvbuf->pskb); + + return ret; +} + +void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup) +{ + enum nl80211_key_type key_type = 0; + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + unsigned long cur_time; + + if (psecuritypriv->last_mic_err_time == 0) { + psecuritypriv->last_mic_err_time = jiffies; + } else { + cur_time = jiffies; + + if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) { + psecuritypriv->btkip_countermeasure = true; + psecuritypriv->last_mic_err_time = 0; + psecuritypriv->btkip_countermeasure_time = cur_time; + } else { + psecuritypriv->last_mic_err_time = jiffies; + } + } + + if (bgroup) + key_type |= NL80211_KEYTYPE_GROUP; + else + key_type |= NL80211_KEYTYPE_PAIRWISE; + + cfg80211_michael_mic_failure(padapter->pnetdev, + (u8 *)&pmlmepriv->assoc_bssid[0], + key_type, -1, NULL, GFP_ATOMIC); + + memset(&ev, 0x00, sizeof(ev)); + if (bgroup) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + + ev.src_addr.sa_family = ARPHRD_ETHER; + ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]); + + memset(&wrqu, 0x00, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); +} + +void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ +} + +int rtw_recv_indicatepkt23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame) +{ + struct recv_priv *precvpriv; + struct rtw_queue *pfree_recv_queue; + struct sk_buff *skb; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + precvpriv = &(padapter->recvpriv); + pfree_recv_queue = &(precvpriv->free_recv_queue); + + skb = precv_frame->pkt; + if (!skb) { + RT_TRACE(_module_recv_osdep_c_, _drv_err_, + ("rtw_recv_indicatepkt23a():skb == NULL!!!!\n")); + goto _recv_indicatepkt_drop; + } + + RT_TRACE(_module_recv_osdep_c_, _drv_info_, + ("rtw_recv_indicatepkt23a():skb != NULL !!!\n")); + RT_TRACE(_module_recv_osdep_c_, _drv_info_, + ("rtw_recv_indicatepkt23a():precv_frame->hdr.rx_data =%p\n", + precv_frame->pkt->data)); + RT_TRACE(_module_recv_osdep_c_, _drv_info_, + ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n", + skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb), skb->len)); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + struct sk_buff *pskb2 = NULL; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct rx_pkt_attrib *pattrib = &precv_frame->attrib; + int bmcast = is_multicast_ether_addr(pattrib->dst); + + /* DBG_8723A("bmcast =%d\n", bmcast); */ + + if (!ether_addr_equal(pattrib->dst, + myid(&padapter->eeprompriv))) { + /* DBG_8723A("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */ + if (bmcast) { + psta = rtw_get_bcmc_stainfo23a(padapter); + pskb2 = skb_clone(skb, GFP_ATOMIC); + } else { + psta = rtw_get_stainfo23a(pstapriv, pattrib->dst); + } + + if (psta) { + struct net_device *pnetdev = padapter->pnetdev; + + /* DBG_8723A("directly forwarding to the rtw_xmit23a_entry23a\n"); */ + + /* skb->ip_summed = CHECKSUM_NONE; */ + skb->dev = pnetdev; + skb_set_queue_mapping(skb, rtw_recv_select_queue23a(skb)); + + rtw_xmit23a_entry23a(skb, pnetdev); + + if (bmcast) + skb = pskb2; + else + goto _recv_indicatepkt_end; + } + } else { /* to APself */ + /* DBG_8723A("to APSelf\n"); */ + } + } + + skb->ip_summed = CHECKSUM_NONE; + skb->dev = padapter->pnetdev; + skb->protocol = eth_type_trans(skb, padapter->pnetdev); + + netif_rx(skb); + +_recv_indicatepkt_end: + + precv_frame->pkt = NULL; /* pointers to NULL before rtw_free_recvframe23a() */ + + rtw_free_recvframe23a(precv_frame, pfree_recv_queue); + + RT_TRACE(_module_recv_osdep_c_, _drv_info_, + ("\n rtw_recv_indicatepkt23a :after netif_rx!!!!\n")); + return _SUCCESS; + +_recv_indicatepkt_drop: + + rtw_free_recvframe23a(precv_frame, pfree_recv_queue); + return _FAIL; +} + +void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + + /* free skb in recv_buf */ + dev_kfree_skb_any(precvbuf->pskb); + + precvbuf->pskb = NULL; + + rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, precvbuf); +} + +void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl) +{ + setup_timer(&preorder_ctrl->reordering_ctrl_timer, + rtw_reordering_ctrl_timeout_handler23a, + (unsigned long)preorder_ctrl); +} diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c new file mode 100644 index 000000000000..040bf29b9d06 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c @@ -0,0 +1,836 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _HCI_INTF_C_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int rtw_suspend(struct usb_interface *intf, pm_message_t message); +static int rtw_resume(struct usb_interface *intf); +static int rtw_drv_init(struct usb_interface *pusb_intf, + const struct usb_device_id *pdid); +static void rtw_disconnect(struct usb_interface *pusb_intf); + +#define USB_VENDER_ID_REALTEK 0x0BDA + +#define RTL8723A_USB_IDS \ + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x8724, \ + 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x1724, \ + 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \ + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0724, \ + 0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ + +static struct usb_device_id rtl8723a_usb_id_tbl[] = { + RTL8723A_USB_IDS + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, rtl8723a_usb_id_tbl); + +static struct usb_driver rtl8723a_usb_drv = { + .name = (char *)"rtl8723au", + .probe = rtw_drv_init, + .disconnect = rtw_disconnect, + .id_table = rtl8723a_usb_id_tbl, + .suspend = rtw_suspend, + .resume = rtw_resume, + .reset_resume = rtw_resume, +}; + +static struct usb_driver *usb_drv = &rtl8723a_usb_drv; + +static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) +{ + return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; +} + +static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) +{ + return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; +} + +static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT; +} + +static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK; +} + +static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) +{ + return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd); +} + +static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) +{ + return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd); +} + +static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) +{ + return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd); +} + +static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj) +{ + u8 rst = _SUCCESS; + + mutex_init(&dvobj->usb_vendor_req_mutex); + dvobj->usb_alloc_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE, + GFP_KERNEL); + if (dvobj->usb_alloc_vendor_req_buf == NULL) { + DBG_8723A("alloc usb_vendor_req_buf failed... /n"); + rst = _FAIL; + goto exit; + } + dvobj->usb_vendor_req_buf = + PTR_ALIGN(dvobj->usb_alloc_vendor_req_buf, ALIGNMENT_UNIT); +exit: + return rst; +} + +static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj) +{ + u8 rst = _SUCCESS; + + kfree(dvobj->usb_alloc_vendor_req_buf); + + mutex_destroy(&dvobj->usb_vendor_req_mutex); + + return rst; +} + +static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) +{ + struct dvobj_priv *pdvobjpriv; + struct usb_device_descriptor *pdev_desc; + struct usb_host_config *phost_conf; + struct usb_config_descriptor *pconf_desc; + struct usb_host_interface *phost_iface; + struct usb_interface_descriptor *piface_desc; + struct usb_host_endpoint *phost_endp; + struct usb_endpoint_descriptor *pendp_desc; + struct usb_device *pusbd; + int i; + int status = _FAIL; + + pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); + if (!pdvobjpriv) + goto exit; + + mutex_init(&pdvobjpriv->hw_init_mutex); + mutex_init(&pdvobjpriv->h2c_fwcmd_mutex); + mutex_init(&pdvobjpriv->setch_mutex); + mutex_init(&pdvobjpriv->setbw_mutex); + + pdvobjpriv->pusbintf = usb_intf; + pusbd = interface_to_usbdev(usb_intf); + pdvobjpriv->pusbdev = pusbd; + usb_set_intfdata(usb_intf, pdvobjpriv); + + pdvobjpriv->RtNumInPipes = 0; + pdvobjpriv->RtNumOutPipes = 0; + + pdev_desc = &pusbd->descriptor; + + phost_conf = pusbd->actconfig; + pconf_desc = &phost_conf->desc; + + phost_iface = &usb_intf->altsetting[0]; + piface_desc = &phost_iface->desc; + + pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces; + pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber; + pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; + + for (i = 0; i < pdvobjpriv->nr_endpoint; i++) { + phost_endp = phost_iface->endpoint + i; + if (phost_endp) { + pendp_desc = &phost_endp->desc; + + DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i); + DBG_8723A("bLength =%x\n", pendp_desc->bLength); + DBG_8723A("bDescriptorType =%x\n", + pendp_desc->bDescriptorType); + DBG_8723A("bEndpointAddress =%x\n", + pendp_desc->bEndpointAddress); + DBG_8723A("wMaxPacketSize =%d\n", + le16_to_cpu(pendp_desc->wMaxPacketSize)); + DBG_8723A("bInterval =%x\n", pendp_desc->bInterval); + + if (RT_usb_endpoint_is_bulk_in(pendp_desc)) { + DBG_8723A("RT_usb_endpoint_is_bulk_in = %x\n", + RT_usb_endpoint_num(pendp_desc)); + pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = + RT_usb_endpoint_num(pendp_desc); + pdvobjpriv->RtNumInPipes++; + } else if (RT_usb_endpoint_is_int_in(pendp_desc)) { + DBG_8723A("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", + RT_usb_endpoint_num(pendp_desc), + pendp_desc->bInterval); + pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = + RT_usb_endpoint_num(pendp_desc); + pdvobjpriv->RtNumInPipes++; + } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) { + DBG_8723A("RT_usb_endpoint_is_bulk_out = %x\n", + RT_usb_endpoint_num(pendp_desc)); + pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = + RT_usb_endpoint_num(pendp_desc); + pdvobjpriv->RtNumOutPipes++; + } + pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc); + } + } + DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n", + pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, + pdvobjpriv->RtNumOutPipes); + + if (pusbd->speed == USB_SPEED_HIGH) { + pdvobjpriv->ishighspeed = true; + DBG_8723A("USB_SPEED_HIGH\n"); + } else { + pdvobjpriv->ishighspeed = false; + DBG_8723A("NON USB_SPEED_HIGH\n"); + } + + if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) { + RT_TRACE(_module_os_intfs_c_, _drv_err_, + ("\n Can't INIT rtw_init_intf_priv\n")); + goto free_dvobj; + } + /* 3 misc */ + sema_init(&(pdvobjpriv->usb_suspend_sema), 0); + rtw_reset_continual_urb_error(pdvobjpriv); + usb_get_dev(pusbd); + status = _SUCCESS; +free_dvobj: + if (status != _SUCCESS && pdvobjpriv) { + usb_set_intfdata(usb_intf, NULL); + mutex_destroy(&pdvobjpriv->hw_init_mutex); + mutex_destroy(&pdvobjpriv->h2c_fwcmd_mutex); + mutex_destroy(&pdvobjpriv->setch_mutex); + mutex_destroy(&pdvobjpriv->setbw_mutex); + kfree(pdvobjpriv); + pdvobjpriv = NULL; + } +exit: + return pdvobjpriv; +} + +static void usb_dvobj_deinit(struct usb_interface *usb_intf) +{ + struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); + + usb_set_intfdata(usb_intf, NULL); + if (dvobj) { + /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */ + if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3) || + (dvobj->InterfaceNumber == 1)) { + if (interface_to_usbdev(usb_intf)->state != + USB_STATE_NOTATTACHED) { + /* If we didn't unplug usb dongle and + * remove/insert module, driver fails on + * sitesurvey for the first time when + * device is up . + * Reset usb port for sitesurvey fail issue. + */ + DBG_8723A("usb attached..., try to reset usb device\n"); + usb_reset_device(interface_to_usbdev(usb_intf)); + } + } + rtw_deinit_intf_priv(dvobj); + mutex_destroy(&dvobj->hw_init_mutex); + mutex_destroy(&dvobj->h2c_fwcmd_mutex); + mutex_destroy(&dvobj->setch_mutex); + mutex_destroy(&dvobj->setbw_mutex); + kfree(dvobj); + } + usb_put_dev(interface_to_usbdev(usb_intf)); +} + +static void decide_chip_type_by_usb_device_id(struct rtw_adapter *padapter, + const struct usb_device_id *pdid) +{ + padapter->chip_type = NULL_CHIP_TYPE; + hal_set_hw_type(padapter); +} + +static void usb_intf_start(struct rtw_adapter *padapter) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_start\n")); + rtw_hal_inirp_init23a(padapter); + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_start\n")); +} + +static void usb_intf_stop(struct rtw_adapter *padapter) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n")); + + /* disable_hw_interrupt */ + if (!padapter->bSurpriseRemoved) { + /* device still exists, so driver can do i/o operation + * TODO: + */ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("SurpriseRemoved == false\n")); + } + + /* cancel in irp */ + rtw_hal_inirp_deinit23a(padapter); + + /* cancel out irp */ + rtw_write_port_cancel(padapter); + + /* todo:cancel other irps */ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n")); +} + +static void rtw_dev_unload(struct rtw_adapter *padapter) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n")); + + if (padapter->bup) { + DBG_8723A("===> rtw_dev_unload\n"); + + padapter->bDriverStopped = true; + if (padapter->xmitpriv.ack_tx) + rtw_ack_tx_done23a(&padapter->xmitpriv, + RTW_SCTX_DONE_DRV_STOP); + + /* s3. */ + if (padapter->intf_stop) + padapter->intf_stop(padapter); + + /* s4. */ + if (!padapter->pwrctrlpriv.bInternalAutoSuspend) + rtw_stop_drv_threads23a(padapter); + + /* s5. */ + if (!padapter->bSurpriseRemoved) { + rtw_hal_deinit23a(padapter); + padapter->bSurpriseRemoved = true; + } + padapter->bup = false; + } else { + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("r871x_dev_unload():padapter->bup == false\n")); + } + DBG_8723A("<=== rtw_dev_unload\n"); + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n")); +} + +int rtw_hw_suspend23a(struct rtw_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct net_device *pnetdev = padapter->pnetdev; + + if ((!padapter->bup) || (padapter->bDriverStopped) || + (padapter->bSurpriseRemoved)) { + DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", + padapter->bup, padapter->bDriverStopped, + padapter->bSurpriseRemoved); + goto error_exit; + } + + if (padapter) { /* system suspend */ + LeaveAllPowerSaveMode23a(padapter); + + DBG_8723A("==> rtw_hw_suspend23a\n"); + down(&pwrpriv->lock); + pwrpriv->bips_processing = true; + /* padapter->net_closed = true; */ + /* s1. */ + if (pnetdev) { + netif_carrier_off(pnetdev); + netif_tx_stop_all_queues(pnetdev); + } + + /* s2. */ + rtw_disassoc_cmd23a(padapter, 500, false); + + /* s2-2. indicate disconnect to os */ + /* rtw_indicate_disconnect23a(padapter); */ + { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + _clr_fwstate_(pmlmepriv, _FW_LINKED); + + rtw_led_control(padapter, LED_CTL_NO_LINK); + + rtw_os_indicate_disconnect23a(padapter); + + /* donnot enqueue cmd */ + rtw_lps_ctrl_wk_cmd23a(padapter, + LPS_CTRL_DISCONNECT, 0); + } + } + /* s2-3. */ + rtw_free_assoc_resources23a(padapter, 1); + + /* s2-4. */ + rtw_free_network_queue23a(padapter, true); + rtw_ips_dev_unload23a(padapter); + pwrpriv->rf_pwrstate = rf_off; + pwrpriv->bips_processing = false; + up(&pwrpriv->lock); + } else { + goto error_exit; + } + return 0; +error_exit: + DBG_8723A("%s, failed\n", __func__); + return -1; +} + +int rtw_hw_resume23a(struct rtw_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + struct net_device *pnetdev = padapter->pnetdev; + + if (padapter) { /* system resume */ + DBG_8723A("==> rtw_hw_resume23a\n"); + down(&pwrpriv->lock); + pwrpriv->bips_processing = true; + rtw_reset_drv_sw23a(padapter); + + if (pm_netdev_open23a(pnetdev, false)) { + up(&pwrpriv->lock); + goto error_exit; + } + + netif_device_attach(pnetdev); + netif_carrier_on(pnetdev); + + if (!rtw_netif_queue_stopped(pnetdev)) + netif_tx_start_all_queues(pnetdev); + else + netif_tx_wake_all_queues(pnetdev); + + pwrpriv->bkeepfwalive = false; + pwrpriv->brfoffbyhw = false; + + pwrpriv->rf_pwrstate = rf_on; + pwrpriv->bips_processing = false; + + up(&pwrpriv->lock); + } else { + goto error_exit; + } + return 0; +error_exit: + DBG_8723A("%s, Open net dev failed\n", __func__); + return -1; +} + +static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) +{ + struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); + struct rtw_adapter *padapter = dvobj->if1; + struct net_device *pnetdev = padapter->pnetdev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + int ret = 0; + unsigned long start_time = jiffies; + + DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + + if ((!padapter->bup) || (padapter->bDriverStopped) || + (padapter->bSurpriseRemoved)) { + DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n", + padapter->bup, padapter->bDriverStopped, + padapter->bSurpriseRemoved); + goto exit; + } + pwrpriv->bInSuspend = true; + rtw_cancel_all_timer23a(padapter); + LeaveAllPowerSaveMode23a(padapter); + + down(&pwrpriv->lock); + /* padapter->net_closed = true; */ + /* s1. */ + if (pnetdev) { + netif_carrier_off(pnetdev); + netif_tx_stop_all_queues(pnetdev); + } + + /* s2. */ + rtw_disassoc_cmd23a(padapter, 0, false); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && + check_fwstate(pmlmepriv, _FW_LINKED)) { + DBG_8723A("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", + __func__, __LINE__, + pmlmepriv->cur_network.network.Ssid.ssid, + pmlmepriv->cur_network.network.MacAddress, + pmlmepriv->cur_network.network.Ssid.ssid_len, + pmlmepriv->assoc_ssid.ssid_len); + + rtw_set_roaming(padapter, 1); + } + /* s2-2. indicate disconnect to os */ + rtw_indicate_disconnect23a(padapter); + /* s2-3. */ + rtw_free_assoc_resources23a(padapter, 1); + /* s2-4. */ + rtw_free_network_queue23a(padapter, true); + + rtw_dev_unload(padapter); + up(&pwrpriv->lock); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + rtw_indicate_scan_done23a(padapter, 1); + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) + rtw_indicate_disconnect23a(padapter); + +exit: + DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, + ret, jiffies_to_msecs(jiffies - start_time)); + + return ret; +} + +static int rtw_resume(struct usb_interface *pusb_intf) +{ + struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); + struct rtw_adapter *padapter = dvobj->if1; + struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; + int ret = 0; + + if (pwrpriv->bInternalAutoSuspend) + ret = rtw_resume_process23a(padapter); + else + ret = rtw_resume_process23a(padapter); + + return ret; +} + +int rtw_resume_process23a(struct rtw_adapter *padapter) +{ + struct net_device *pnetdev; + struct pwrctrl_priv *pwrpriv = NULL; + int ret = -1; + unsigned long start_time = jiffies; + + DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + + if (!padapter) + goto exit; + pnetdev = padapter->pnetdev; + pwrpriv = &padapter->pwrctrlpriv; + + down(&pwrpriv->lock); + rtw_reset_drv_sw23a(padapter); + pwrpriv->bkeepfwalive = false; + + DBG_8723A("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); + if (pm_netdev_open23a(pnetdev, true) != 0) + goto exit; + + netif_device_attach(pnetdev); + netif_carrier_on(pnetdev); + + up(&pwrpriv->lock); + + if (padapter->pid[1] != 0) { + DBG_8723A("pid[1]:%d\n", padapter->pid[1]); + rtw_signal_process(padapter->pid[1], SIGUSR2); + } + + rtw23a_roaming(padapter, NULL); + + ret = 0; +exit: + if (pwrpriv) + pwrpriv->bInSuspend = false; + DBG_8723A("<=== %s return %d.............. in %dms\n", __func__, + ret, jiffies_to_msecs(jiffies - start_time)); + + return ret; +} + +/* + * drv_init() - a device potentially for us + * + * notes: drv_init() is called when the bus driver has located a card + * for us to support. + * We accept the new device by returning 0. + */ +static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, + struct usb_interface *pusb_intf, + const struct usb_device_id *pdid) +{ + struct rtw_adapter *padapter = NULL; + struct net_device *pnetdev = NULL; + int status = _FAIL; + + pnetdev = rtw_init_netdev23a(padapter); + if (!pnetdev) + goto handle_dualmac; + padapter = netdev_priv(pnetdev); + + padapter->dvobj = dvobj; + padapter->bDriverStopped = true; + dvobj->if1 = padapter; + dvobj->padapters[dvobj->iface_nums++] = padapter; + padapter->iface_id = IFACE_ID0; + + /* step 1-1., decide the chip_type via vid/pid */ + decide_chip_type_by_usb_device_id(padapter, pdid); + + if (rtw_handle_dualmac23a(padapter, 1) != _SUCCESS) + goto free_adapter; + + SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); + + if (rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj))) + goto handle_dualmac; + + /* step 2. hook HalFunc, allocate HalData */ + if (rtl8723au_set_hal_ops(padapter)) + return NULL; + + padapter->intf_start = &usb_intf_start; + padapter->intf_stop = &usb_intf_stop; + + /* step init_io_priv */ + rtw_init_io_priv23a(padapter, usb_set_intf_ops); + + /* step read_chip_version */ + rtw_hal_read_chip_version23a(padapter); + + /* step usb endpoint mapping */ + rtw_hal_chip_configure23a(padapter); + + /* step read efuse/eeprom data and get mac_addr */ + rtw_hal_read_chip_info23a(padapter); + + /* step 5. */ + if (rtw_init_drv_sw23a(padapter) == _FAIL) { + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("Initialize driver software resource Failed!\n")); + goto free_hal_data; + } + +#ifdef CONFIG_PM + if (padapter->pwrctrlpriv.bSupportRemoteWakeup) { + dvobj->pusbdev->do_remote_wakeup = 1; + pusb_intf->needs_remote_wakeup = 1; + device_init_wakeup(&pusb_intf->dev, 1); + DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); + DBG_8723A("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", + device_may_wakeup(&pusb_intf->dev)); + } +#endif + /* 2012-07-11 Move here to prevent the 8723AS-VAU BT + * auto suspend influence + */ + if (usb_autopm_get_interface(pusb_intf) < 0) + DBG_8723A("can't get autopm:\n"); +#ifdef CONFIG_8723AU_BT_COEXIST + padapter->pwrctrlpriv.autopm_cnt = 1; +#endif + + /* set mac addr */ + rtw_macaddr_cfg23a(padapter->eeprompriv.mac_addr); + rtw_init_wifidirect_addrs23a(padapter, padapter->eeprompriv.mac_addr, + padapter->eeprompriv.mac_addr); + + DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n", + padapter->bDriverStopped, padapter->bSurpriseRemoved, + padapter->bup, padapter->hw_init_completed + ); + status = _SUCCESS; + +free_hal_data: + if (status != _SUCCESS) + kfree(padapter->HalData); + if (status != _SUCCESS) { + rtw_wdev_unregister(padapter->rtw_wdev); + rtw_wdev_free(padapter->rtw_wdev); + } +handle_dualmac: + if (status != _SUCCESS) + rtw_handle_dualmac23a(padapter, 0); +free_adapter: + if (status != _SUCCESS) { + if (pnetdev) + free_netdev(pnetdev); + padapter = NULL; + } + return padapter; +} + +static void rtw_usb_if1_deinit(struct rtw_adapter *if1) +{ + struct net_device *pnetdev = if1->pnetdev; + struct mlme_priv *pmlmepriv = &if1->mlmepriv; + + if (check_fwstate(pmlmepriv, _FW_LINKED)) + rtw_disassoc_cmd23a(if1, 0, false); + +#ifdef CONFIG_8723AU_AP_MODE + free_mlme_ap_info23a(if1); +#endif + + if (pnetdev) + unregister_netdev(pnetdev); /* will call netdev_close() */ + + rtw_cancel_all_timer23a(if1); + + rtw_dev_unload(if1); + + DBG_8723A("+r871xu_dev_remove, hw_init_completed =%d\n", + if1->hw_init_completed); + + rtw_handle_dualmac23a(if1, 0); + + if (if1->rtw_wdev) { + rtw_wdev_unregister(if1->rtw_wdev); + rtw_wdev_free(if1->rtw_wdev); + } + +#ifdef CONFIG_8723AU_BT_COEXIST + if (1 == if1->pwrctrlpriv.autopm_cnt) { + usb_autopm_put_interface(adapter_to_dvobj(if1)->pusbintf); + if1->pwrctrlpriv.autopm_cnt--; + } +#endif + + rtw_free_drv_sw23a(if1); + + if (pnetdev) + free_netdev(pnetdev); +} + +static int rtw_drv_init(struct usb_interface *pusb_intf, + const struct usb_device_id *pdid) +{ + struct rtw_adapter *if1 = NULL; + struct dvobj_priv *dvobj; + int status = _FAIL; + + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); + + /* Initialize dvobj_priv */ + dvobj = usb_dvobj_init(pusb_intf); + if (!dvobj) { + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("initialize device object priv Failed!\n")); + goto exit; + } + + if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid); + if (!if1) { + DBG_8723A("rtw_init_primary_adapter Failed!\n"); + goto free_dvobj; + } + + /* dev_alloc_name && register_netdev */ + status = rtw_drv_register_netdev(if1); + if (status != _SUCCESS) + goto free_if1; + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("-871x_drv - drv_init, success!\n")); + + status = _SUCCESS; + +free_if1: + if (status != _SUCCESS && if1) + rtw_usb_if1_deinit(if1); +free_dvobj: + if (status != _SUCCESS) + usb_dvobj_deinit(pusb_intf); +exit: + return status == _SUCCESS ? 0 : -ENODEV; +} + +/* dev_remove() - our device is being removed */ +static void rtw_disconnect(struct usb_interface *pusb_intf) +{ + struct dvobj_priv *dvobj; + struct rtw_adapter *padapter; + struct net_device *pnetdev; + struct mlme_priv *pmlmepriv; + + dvobj = usb_get_intfdata(pusb_intf); + if (!dvobj) + return; + + padapter = dvobj->if1; + pnetdev = padapter->pnetdev; + pmlmepriv = &padapter->mlmepriv; + + usb_set_intfdata(pusb_intf, NULL); + + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n")); + + rtw_pm_set_ips23a(padapter, IPS_NONE); + rtw_pm_set_lps23a(padapter, PS_MODE_ACTIVE); + + LeaveAllPowerSaveMode23a(padapter); + + rtw_usb_if1_deinit(padapter); + + usb_dvobj_deinit(pusb_intf); + + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n")); + DBG_8723A("-r871xu_dev_remove, done\n"); + + return; +} + +extern int console_suspend_enabled; + +static int __init rtw_drv_entry(void) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n")); + rtw_suspend_lock_init(); + return usb_register(usb_drv); +} + +static void __exit rtw_drv_halt(void) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n")); + DBG_8723A("+rtw_drv_halt\n"); + + rtw_suspend_lock_uninit(); + + usb_deregister(usb_drv); + + DBG_8723A("-rtw_drv_halt\n"); +} + +module_init(rtw_drv_entry); +module_exit(rtw_drv_halt); diff --git a/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c new file mode 100644 index 000000000000..c49160e477d8 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c @@ -0,0 +1,283 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _USB_OPS_LINUX_C_ + +#include +#include +#include + +unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr) +{ + struct usb_device *pusbd = pdvobj->pusbdev; + unsigned int pipe = 0, ep_num = 0; + + if (addr == RECV_BULK_IN_ADDR) { + pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); + } else if (addr == RECV_INT_IN_ADDR) { + pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); + } else if (addr < HW_QUEUE_ENTRY) { + ep_num = pdvobj->Queue2Pipe[addr]; + pipe = usb_sndbulkpipe(pusbd, ep_num); + } + return pipe; +} + +struct zero_bulkout_context { + void *pbuf; + void *purb; + void *pirp; + void *padapter; +}; + +void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) +{ +} + +void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) +{ +} + +void usb_read_port_cancel23a(struct intf_hdl *pintfhdl) +{ + struct recv_buf *precvbuf; + struct rtw_adapter *padapter = pintfhdl->padapter; + int i; + + precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; + + DBG_8723A("%s\n", __func__); + + padapter->bReadPortCancel = true; + + for (i = 0; i < NR_RECVBUFF ; i++) { + if (precvbuf->purb) + usb_kill_urb(precvbuf->purb); + precvbuf++; + } + usb_kill_urb(padapter->recvpriv.int_in_urb); +} + +static void usb_write_port23a_complete(struct urb *purb, struct pt_regs *regs) +{ + struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; + struct rtw_adapter *padapter = pxmitbuf->padapter; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct hal_data_8723a *phaldata; + unsigned long irqL; + + switch (pxmitbuf->flags) { + case VO_QUEUE_INX: + pxmitpriv->voq_cnt--; + break; + case VI_QUEUE_INX: + pxmitpriv->viq_cnt--; + break; + case BE_QUEUE_INX: + pxmitpriv->beq_cnt--; + break; + case BK_QUEUE_INX: + pxmitpriv->bkq_cnt--; + break; + case HIGH_QUEUE_INX: +#ifdef CONFIG_8723AU_AP_MODE + rtw_chk_hi_queue_cmd23a(padapter); +#endif + break; + default: + break; + } + + if (padapter->bSurpriseRemoved || padapter->bDriverStopped || + padapter->bWritePortCancel) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", + padapter->bDriverStopped, padapter->bSurpriseRemoved)); + DBG_8723A("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", + __func__, padapter->bDriverStopped, + padapter->bSurpriseRemoved, padapter->bReadPortCancel, + pxmitbuf->ext_tag); + + goto check_completion; + } + + if (purb->status) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete : purb->status(%d) != 0\n", + purb->status)); + DBG_8723A("###=> urb_write_port_complete status(%d)\n", + purb->status); + if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) { + sreset_set_wifi_error_status23a(padapter, + USB_WRITE_PORT_FAIL); + } else if (purb->status == -EINPROGRESS) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete: EINPROGESS\n")); + goto check_completion; + } else if (purb->status == -ENOENT) { + DBG_8723A("%s: -ENOENT\n", __func__); + goto check_completion; + } else if (purb->status == -ECONNRESET) { + DBG_8723A("%s: -ECONNRESET\n", __func__); + goto check_completion; + } else if (purb->status == -ESHUTDOWN) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete: ESHUTDOWN\n")); + padapter->bDriverStopped = true; + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete:bDriverStopped = true\n")); + goto check_completion; + } else { + padapter->bSurpriseRemoved = true; + DBG_8723A("bSurpriseRemoved = true\n"); + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a_complete:bSurpriseRemoved = true\n")); + goto check_completion; + } + } + phaldata = GET_HAL_DATA(padapter); + phaldata->srestpriv.last_tx_complete_time = jiffies; + +check_completion: + spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL); + rtw23a_sctx_done_err(&pxmitbuf->sctx, + purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : + RTW_SCTX_DONE_SUCCESS); + spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL); + + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); +} + +u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + struct xmit_buf *pxmitbuf) +{ + struct urb *purb = NULL; + struct rtw_adapter *padapter = (struct rtw_adapter *)pintfhdl->padapter; + struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; + struct usb_device *pusbd = pdvobj->pusbdev; + unsigned long irqL; + unsigned int pipe; + int status; + u32 ret = _FAIL; + + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port23a\n")); + + if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || + (padapter->pwrctrlpriv.pnp_bstop_trx)) { + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); + goto exit; + } + + spin_lock_irqsave(&pxmitpriv->lock, irqL); + + switch (addr) { + case VO_QUEUE_INX: + pxmitpriv->voq_cnt++; + pxmitbuf->flags = VO_QUEUE_INX; + break; + case VI_QUEUE_INX: + pxmitpriv->viq_cnt++; + pxmitbuf->flags = VI_QUEUE_INX; + break; + case BE_QUEUE_INX: + pxmitpriv->beq_cnt++; + pxmitbuf->flags = BE_QUEUE_INX; + break; + case BK_QUEUE_INX: + pxmitpriv->bkq_cnt++; + pxmitbuf->flags = BK_QUEUE_INX; + break; + case HIGH_QUEUE_INX: + pxmitbuf->flags = HIGH_QUEUE_INX; + break; + default: + pxmitbuf->flags = MGT_QUEUE_INX; + break; + } + + spin_unlock_irqrestore(&pxmitpriv->lock, irqL); + + purb = pxmitbuf->pxmit_urb[0]; + + /* translate DMA FIFO addr to pipehandle */ + pipe = ffaddr2pipehdl23a(pdvobj, addr); + + usb_fill_bulk_urb(purb, pusbd, pipe, + pxmitframe->buf_addr, /* pxmitbuf->pbuf */ + cnt, usb_write_port23a_complete, + pxmitbuf);/* context is pxmitbuf */ + + status = usb_submit_urb(purb, GFP_ATOMIC); + if (!status) { + struct hal_data_8723a *phaldata = GET_HAL_DATA(padapter); + phaldata->srestpriv.last_tx_time = jiffies; + } else { + rtw23a_sctx_done_err(&pxmitbuf->sctx, + RTW_SCTX_DONE_WRITE_PORT_ERR); + DBG_8723A("usb_write_port23a, status =%d\n", status); + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, + ("usb_write_port23a(): usb_submit_urb, status =%x\n", + status)); + + switch (status) { + case -ENODEV: + padapter->bDriverStopped = true; + break; + default: + break; + } + goto exit; + } + ret = _SUCCESS; + RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port23a\n")); + +exit: + if (ret != _SUCCESS) + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + + return ret; +} + +void usb_write_port23a_cancel(struct intf_hdl *pintfhdl) +{ + struct rtw_adapter *padapter = pintfhdl->padapter; + struct xmit_buf *pxmitbuf; + struct list_head *plist; + int j; + + DBG_8723A("%s\n", __func__); + + padapter->bWritePortCancel = true; + + list_for_each(plist, &padapter->xmitpriv.xmitbuf_list) { + pxmitbuf = container_of(plist, struct xmit_buf, list2); + for (j = 0; j < 8; j++) { + if (pxmitbuf->pxmit_urb[j]) + usb_kill_urb(pxmitbuf->pxmit_urb[j]); + } + } + list_for_each(plist, &padapter->xmitpriv.xmitextbuf_list) { + pxmitbuf = container_of(plist, struct xmit_buf, list2); + for (j = 0; j < 8; j++) { + if (pxmitbuf->pxmit_urb[j]) + usb_kill_urb(pxmitbuf->pxmit_urb[j]); + } + } +} diff --git a/drivers/staging/rtl8723au/os_dep/xmit_linux.c b/drivers/staging/rtl8723au/os_dep/xmit_linux.c new file mode 100644 index 000000000000..e1c6fc746233 --- /dev/null +++ b/drivers/staging/rtl8723au/os_dep/xmit_linux.c @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#define _XMIT_OSDEP_C_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +uint rtw_remainder_len23a(struct pkt_file *pfile) +{ + return pfile->buf_len - ((unsigned long)(pfile->cur_addr) - + (unsigned long)(pfile->buf_start)); +} + +void _rtw_open_pktfile23a(struct sk_buff *pktptr, struct pkt_file *pfile) +{ + pfile->pkt = pktptr; + pfile->buf_start = pktptr->data; + pfile->cur_addr = pktptr->data; + pfile->buf_len = pktptr->len; + pfile->pkt_len = pktptr->len; + + pfile->cur_buffer = pfile->buf_start; +} + +uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen) +{ + uint len = 0; + + len = rtw_remainder_len23a(pfile); + len = (rlen > len) ? len : rlen; + + if (rmem) + skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, + rmem, len); + + pfile->cur_addr += len; + pfile->pkt_len -= len; + + return len; +} + +int rtw_endofpktfile23a(struct pkt_file *pfile) +{ + if (pfile->pkt_len == 0) + return true; + return false; +} + +int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter, + struct xmit_buf *pxmitbuf, u32 alloc_sz) +{ + int i; + + pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL); + if (pxmitbuf->pallocated_buf == NULL) + return _FAIL; + + pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ); + + for (i = 0; i < 8; i++) { + pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); + if (pxmitbuf->pxmit_urb[i] == NULL) { + DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL"); + return _FAIL; + } + } + return _SUCCESS; +} + +void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter, + struct xmit_buf *pxmitbuf) +{ + int i; + + for (i = 0; i < 8; i++) + usb_free_urb(pxmitbuf->pxmit_urb[i]); + kfree(pxmitbuf->pallocated_buf); +} + +#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5) + +void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u16 queue; + + queue = skb_get_queue_mapping(pkt); + if (padapter->registrypriv.wifi_spec) { + if (__netif_subqueue_stopped(padapter->pnetdev, queue) && + (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) + netif_wake_subqueue(padapter->pnetdev, queue); + } else { + if (__netif_subqueue_stopped(padapter->pnetdev, queue)) + netif_wake_subqueue(padapter->pnetdev, queue); + } + dev_kfree_skb_any(pkt); +} + +void rtw_os_xmit_complete23a(struct rtw_adapter *padapter, + struct xmit_frame *pxframe) +{ + if (pxframe->pkt) + rtw_os_pkt_complete23a(padapter, pxframe->pkt); + + pxframe->pkt = NULL; +} + +void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter) +{ + struct xmit_priv *pxmitpriv; + + if (!padapter) + return; + pxmitpriv = &padapter->xmitpriv; + + spin_lock_bh(&pxmitpriv->lock); + + if (rtw_txframes_pending23a(padapter)) + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); + spin_unlock_bh(&pxmitpriv->lock); +} + +static void rtw_check_xmit_resource(struct rtw_adapter *padapter, + struct sk_buff *pkt) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u16 queue; + + queue = skb_get_queue_mapping(pkt); + if (padapter->registrypriv.wifi_spec) { + /* No free space for Tx, tx_worker is too slow */ + if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) + netif_stop_subqueue(padapter->pnetdev, queue); + } else { + if (pxmitpriv->free_xmitframe_cnt <= 4) { + if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) + netif_stop_subqueue(padapter->pnetdev, queue); + } + } +} + +int rtw_xmit23a_entry23a(struct sk_buff *skb, struct net_device *pnetdev) +{ + struct rtw_adapter *padapter = netdev_priv(pnetdev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + int res = 0; + + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n")); + + if (!rtw_if_up23a(padapter)) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, + ("rtw_xmit23a_entry23a: rtw_if_up23a fail\n")); + goto drop_packet; + } + + rtw_check_xmit_resource(padapter, skb); + + res = rtw_xmit23a(padapter, skb); + if (res < 0) + goto drop_packet; + + pxmitpriv->tx_pkts++; + RT_TRACE(_module_xmit_osdep_c_, _drv_info_, + ("rtw_xmit23a_entry23a: tx_pkts=%d\n", + (u32)pxmitpriv->tx_pkts)); + goto exit; + +drop_packet: + pxmitpriv->tx_drop++; + dev_kfree_skb_any(skb); + RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, + ("rtw_xmit23a_entry23a: drop, tx_drop=%d\n", + (u32)pxmitpriv->tx_drop)); +exit: + return 0; +} -- cgit v1.2.3 From 364e30ebd2dbaccba430c603da03e68746eb932a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:41 -0500 Subject: staging: r8723au: Add source files for new driver - part 4 The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets. A driver for it has been available in a GitHub repo for several months. This commit contains the fourth part of source files. The source is arbitrarily split to avoid E-mail files that are too large. Jes Sorensen at RedHat has made many improvements to the vendor code, and he has been doing the testing. I do not have access to this device. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/include/Hal8723APhyCfg.h | 234 +++ drivers/staging/rtl8723au/include/Hal8723APhyReg.h | 1078 ++++++++++ drivers/staging/rtl8723au/include/Hal8723PwrSeq.h | 150 ++ .../staging/rtl8723au/include/Hal8723UHWImg_CE.h | 29 + .../staging/rtl8723au/include/HalDMOutSrc8723A.h | 64 + .../staging/rtl8723au/include/HalHWImg8723A_BB.h | 44 + .../staging/rtl8723au/include/HalHWImg8723A_FW.h | 28 + .../staging/rtl8723au/include/HalHWImg8723A_MAC.h | 26 + .../staging/rtl8723au/include/HalHWImg8723A_RF.h | 25 + drivers/staging/rtl8723au/include/HalPwrSeqCmd.h | 130 ++ drivers/staging/rtl8723au/include/HalVerDef.h | 136 ++ drivers/staging/rtl8723au/include/cmd_osdep.h | 26 + drivers/staging/rtl8723au/include/drv_types.h | 364 ++++ drivers/staging/rtl8723au/include/ethernet.h | 22 + drivers/staging/rtl8723au/include/hal_com.h | 211 ++ drivers/staging/rtl8723au/include/hal_intf.h | 392 ++++ drivers/staging/rtl8723au/include/ieee80211.h | 603 ++++++ drivers/staging/rtl8723au/include/ioctl_cfg80211.h | 119 ++ drivers/staging/rtl8723au/include/mlme_osdep.h | 28 + drivers/staging/rtl8723au/include/mp_custom_oid.h | 342 ++++ drivers/staging/rtl8723au/include/odm.h | 1210 +++++++++++ drivers/staging/rtl8723au/include/odm_HWConfig.h | 174 ++ .../staging/rtl8723au/include/odm_RegConfig8723A.h | 34 + .../staging/rtl8723au/include/odm_RegDefine11AC.h | 49 + .../staging/rtl8723au/include/odm_RegDefine11N.h | 165 ++ drivers/staging/rtl8723au/include/odm_debug.h | 139 ++ drivers/staging/rtl8723au/include/odm_interface.h | 131 ++ drivers/staging/rtl8723au/include/odm_precomp.h | 54 + drivers/staging/rtl8723au/include/odm_reg.h | 114 ++ drivers/staging/rtl8723au/include/odm_types.h | 36 + drivers/staging/rtl8723au/include/osdep_intf.h | 46 + drivers/staging/rtl8723au/include/osdep_service.h | 340 +++ drivers/staging/rtl8723au/include/recv_osdep.h | 45 + .../rtl8723au/include/rtl8723a_bt-coexist.h | 1672 +++++++++++++++ drivers/staging/rtl8723au/include/rtl8723a_cmd.h | 160 ++ drivers/staging/rtl8723au/include/rtl8723a_dm.h | 144 ++ drivers/staging/rtl8723au/include/rtl8723a_hal.h | 575 ++++++ drivers/staging/rtl8723au/include/rtl8723a_led.h | 30 + drivers/staging/rtl8723au/include/rtl8723a_pg.h | 107 + drivers/staging/rtl8723au/include/rtl8723a_recv.h | 70 + drivers/staging/rtl8723au/include/rtl8723a_rf.h | 58 + drivers/staging/rtl8723au/include/rtl8723a_spec.h | 2158 ++++++++++++++++++++ .../staging/rtl8723au/include/rtl8723a_sreset.h | 25 + drivers/staging/rtl8723au/include/rtl8723a_xmit.h | 229 +++ drivers/staging/rtl8723au/include/rtw_ap.h | 55 + drivers/staging/rtl8723au/include/rtw_cmd.h | 835 ++++++++ drivers/staging/rtl8723au/include/rtw_debug.h | 192 ++ drivers/staging/rtl8723au/include/rtw_eeprom.h | 135 ++ drivers/staging/rtl8723au/include/rtw_efuse.h | 109 + drivers/staging/rtl8723au/include/rtw_event.h | 114 ++ drivers/staging/rtl8723au/include/rtw_ht.h | 43 + drivers/staging/rtl8723au/include/rtw_io.h | 416 ++++ drivers/staging/rtl8723au/include/rtw_ioctl.h | 26 + drivers/staging/rtl8723au/include/rtw_ioctl_set.h | 39 + drivers/staging/rtl8723au/include/rtw_led.h | 181 ++ drivers/staging/rtl8723au/include/rtw_mlme.h | 632 ++++++ drivers/staging/rtl8723au/include/rtw_mlme_ext.h | 782 +++++++ drivers/staging/rtl8723au/include/rtw_p2p.h | 158 ++ drivers/staging/rtl8723au/include/rtw_pwrctrl.h | 265 +++ drivers/staging/rtl8723au/include/rtw_qos.h | 26 + drivers/staging/rtl8723au/include/rtw_recv.h | 319 +++ drivers/staging/rtl8723au/include/rtw_rf.h | 113 + drivers/staging/rtl8723au/include/rtw_security.h | 357 ++++ drivers/staging/rtl8723au/include/rtw_sreset.h | 56 + drivers/staging/rtl8723au/include/rtw_version.h | 1 + drivers/staging/rtl8723au/include/rtw_xmit.h | 407 ++++ drivers/staging/rtl8723au/include/sta_info.h | 396 ++++ drivers/staging/rtl8723au/include/usb_hal.h | 20 + drivers/staging/rtl8723au/include/usb_ops.h | 97 + drivers/staging/rtl8723au/include/usb_ops_linux.h | 46 + drivers/staging/rtl8723au/include/usb_osintf.h | 24 + drivers/staging/rtl8723au/include/usb_vendor_req.h | 31 + drivers/staging/rtl8723au/include/wifi.h | 707 +++++++ drivers/staging/rtl8723au/include/wlan_bssdef.h | 215 ++ drivers/staging/rtl8723au/include/xmit_osdep.h | 57 + 75 files changed, 18670 insertions(+) create mode 100644 drivers/staging/rtl8723au/include/Hal8723APhyCfg.h create mode 100644 drivers/staging/rtl8723au/include/Hal8723APhyReg.h create mode 100644 drivers/staging/rtl8723au/include/Hal8723PwrSeq.h create mode 100644 drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h create mode 100644 drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h create mode 100644 drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h create mode 100644 drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h create mode 100644 drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h create mode 100644 drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h create mode 100644 drivers/staging/rtl8723au/include/HalPwrSeqCmd.h create mode 100644 drivers/staging/rtl8723au/include/HalVerDef.h create mode 100644 drivers/staging/rtl8723au/include/cmd_osdep.h create mode 100644 drivers/staging/rtl8723au/include/drv_types.h create mode 100644 drivers/staging/rtl8723au/include/ethernet.h create mode 100644 drivers/staging/rtl8723au/include/hal_com.h create mode 100644 drivers/staging/rtl8723au/include/hal_intf.h create mode 100644 drivers/staging/rtl8723au/include/ieee80211.h create mode 100644 drivers/staging/rtl8723au/include/ioctl_cfg80211.h create mode 100644 drivers/staging/rtl8723au/include/mlme_osdep.h create mode 100644 drivers/staging/rtl8723au/include/mp_custom_oid.h create mode 100644 drivers/staging/rtl8723au/include/odm.h create mode 100644 drivers/staging/rtl8723au/include/odm_HWConfig.h create mode 100644 drivers/staging/rtl8723au/include/odm_RegConfig8723A.h create mode 100644 drivers/staging/rtl8723au/include/odm_RegDefine11AC.h create mode 100644 drivers/staging/rtl8723au/include/odm_RegDefine11N.h create mode 100644 drivers/staging/rtl8723au/include/odm_debug.h create mode 100644 drivers/staging/rtl8723au/include/odm_interface.h create mode 100644 drivers/staging/rtl8723au/include/odm_precomp.h create mode 100644 drivers/staging/rtl8723au/include/odm_reg.h create mode 100644 drivers/staging/rtl8723au/include/odm_types.h create mode 100644 drivers/staging/rtl8723au/include/osdep_intf.h create mode 100644 drivers/staging/rtl8723au/include/osdep_service.h create mode 100644 drivers/staging/rtl8723au/include/recv_osdep.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_cmd.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_dm.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_hal.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_led.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_pg.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_recv.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_rf.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_spec.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_sreset.h create mode 100644 drivers/staging/rtl8723au/include/rtl8723a_xmit.h create mode 100644 drivers/staging/rtl8723au/include/rtw_ap.h create mode 100644 drivers/staging/rtl8723au/include/rtw_cmd.h create mode 100644 drivers/staging/rtl8723au/include/rtw_debug.h create mode 100644 drivers/staging/rtl8723au/include/rtw_eeprom.h create mode 100644 drivers/staging/rtl8723au/include/rtw_efuse.h create mode 100644 drivers/staging/rtl8723au/include/rtw_event.h create mode 100644 drivers/staging/rtl8723au/include/rtw_ht.h create mode 100644 drivers/staging/rtl8723au/include/rtw_io.h create mode 100644 drivers/staging/rtl8723au/include/rtw_ioctl.h create mode 100644 drivers/staging/rtl8723au/include/rtw_ioctl_set.h create mode 100644 drivers/staging/rtl8723au/include/rtw_led.h create mode 100644 drivers/staging/rtl8723au/include/rtw_mlme.h create mode 100644 drivers/staging/rtl8723au/include/rtw_mlme_ext.h create mode 100644 drivers/staging/rtl8723au/include/rtw_p2p.h create mode 100644 drivers/staging/rtl8723au/include/rtw_pwrctrl.h create mode 100644 drivers/staging/rtl8723au/include/rtw_qos.h create mode 100644 drivers/staging/rtl8723au/include/rtw_recv.h create mode 100644 drivers/staging/rtl8723au/include/rtw_rf.h create mode 100644 drivers/staging/rtl8723au/include/rtw_security.h create mode 100644 drivers/staging/rtl8723au/include/rtw_sreset.h create mode 100644 drivers/staging/rtl8723au/include/rtw_version.h create mode 100644 drivers/staging/rtl8723au/include/rtw_xmit.h create mode 100644 drivers/staging/rtl8723au/include/sta_info.h create mode 100644 drivers/staging/rtl8723au/include/usb_hal.h create mode 100644 drivers/staging/rtl8723au/include/usb_ops.h create mode 100644 drivers/staging/rtl8723au/include/usb_ops_linux.h create mode 100644 drivers/staging/rtl8723au/include/usb_osintf.h create mode 100644 drivers/staging/rtl8723au/include/usb_vendor_req.h create mode 100644 drivers/staging/rtl8723au/include/wifi.h create mode 100644 drivers/staging/rtl8723au/include/wlan_bssdef.h create mode 100644 drivers/staging/rtl8723au/include/xmit_osdep.h (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h new file mode 100644 index 000000000000..4aa8cdb5fb90 --- /dev/null +++ b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __INC_HAL8723PHYCFG_H__ +#define __INC_HAL8723PHYCFG_H__ + +/*--------------------------Define Parameters-------------------------------*/ +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 /* us */ +#define AntennaDiversityValue 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define Reset_Cnt_Limit 3 + + +#define MAX_AGGR_NUM 0x0909 + +/*--------------------------Define Parameters-------------------------------*/ + + +/*------------------------------Define structure----------------------------*/ +enum swchnlcmdid { + CmdID_End, + CmdID_SetTxPowerLevel, + CmdID_BBRegWrite10, + CmdID_WritePortUlong, + CmdID_WritePortUshort, + CmdID_WritePortUchar, + CmdID_RF_WriteReg, +}; + + +/* 1. Switch channel related */ +struct swchnlcmd { + enum swchnlcmdid CmdID; + u32 Para1; + u32 Para2; + u32 msDelay; +}; + +enum HW90_BLOCK { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, /* Never use this */ +}; + +enum RF_RADIO_PATH { + RF_PATH_A = 0, /* Radio Path A */ + RF_PATH_B = 1, /* Radio Path B */ + RF_PATH_C = 2, /* Radio Path C */ + RF_PATH_D = 3, /* Radio Path D */ + RF_PATH_MAX /* Max RF number 90 support */ +}; + +#define RF_PATH_MAX 3 + +#define CHANNEL_MAX_NUMBER 14 /* 14 is the max channel number */ +#define CHANNEL_GROUP_MAX 3 /* ch1~3, ch4~9, ch10~14 total three groups */ + +enum WIRELESS_MODE { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = BIT2, + WIRELESS_MODE_B = BIT0, + WIRELESS_MODE_G = BIT1, + WIRELESS_MODE_AUTO = BIT5, + WIRELESS_MODE_N_24G = BIT3, + WIRELESS_MODE_N_5G = BIT4, + WIRELESS_MODE_AC = BIT6 +}; + +enum baseband_config_type { + BaseBand_Config_PHY_REG = 0, /* Radio Path A */ + BaseBand_Config_AGC_TAB = 1, /* Radio Path B */ +}; + +enum ra_offset_area { + RA_OFFSET_LEGACY_OFDM1, + RA_OFFSET_LEGACY_OFDM2, + RA_OFFSET_HT_OFDM1, + RA_OFFSET_HT_OFDM2, + RA_OFFSET_HT_OFDM3, + RA_OFFSET_HT_OFDM4, + RA_OFFSET_HT_CCK, +}; + + +/* BB/RF related */ +enum rf_type_8190p { + RF_TYPE_MIN, /* 0 */ + RF_8225 = 1, /* 1 11b/g RF for verification only */ + RF_8256 = 2, /* 2 11b/g/n */ + RF_8258 = 3, /* 3 11a/b/g/n RF */ + RF_6052 = 4, /* 4 11b/g/n RF */ + RF_PSEUDO_11N = 5, /* 5, It is a temporality RF. */ +}; + +struct bb_reg_define { + u32 rfintfs; /* set software control: */ + /* 0x870~0x877[8 bytes] */ + u32 rfintfi; /* readback data: */ + /* 0x8e0~0x8e7[8 bytes] */ + u32 rfintfo; /* output data: */ + /* 0x860~0x86f [16 bytes] */ + u32 rfintfe; /* output enable: */ + /* 0x860~0x86f [16 bytes] */ + u32 rf3wireOffset; /* LSSI data: */ + /* 0x840~0x84f [16 bytes] */ + u32 rfLSSI_Select; /* BB Band Select: */ + /* 0x878~0x87f [8 bytes] */ + u32 rfTxGainStage; /* Tx gain stage: */ + /* 0x80c~0x80f [4 bytes] */ + u32 rfHSSIPara1; /* wire parameter control1 : */ + /* 0x820~0x823, 0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] */ + u32 rfHSSIPara2; /* wire parameter control2 : */ + /* 0x824~0x827, 0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] */ + u32 rfSwitchControl; /* Tx Rx antenna control : */ + /* 0x858~0x85f [16 bytes] */ + u32 rfAGCControl1; /* AGC parameter control1 : */ + /* 0xc50~0xc53, 0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] */ + u32 rfAGCControl2; /* AGC parameter control2 : */ + /* 0xc54~0xc57, 0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] */ + u32 rfRxIQImbalance; /* OFDM Rx IQ imbalance matrix : */ + /* 0xc14~0xc17, 0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] */ + u32 rfRxAFE; /* Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : */ + /* 0xc10~0xc13, 0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] */ + u32 rfTxIQImbalance; /* OFDM Tx IQ imbalance matrix */ + /* 0xc80~0xc83, 0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] */ + u32 rfTxAFE; /* Tx IQ DC Offset and Tx DFIR type */ + /* 0xc84~0xc87, 0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] */ + u32 rfLSSIReadBack; /* LSSI RF readback data SI mode */ + /* 0x8a0~0x8af [16 bytes] */ + u32 rfLSSIReadBackPi; /* LSSI RF readback data PI mode 0x8b8-8bc for Path A and B */ +}; + +struct r_antenna_sel_ofdm { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 OFDM_TXSC:2; + u32 Reserved:2; +}; + +struct r_antenna_sel_cck { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +/*------------------------Export global variable----------------------------*/ + + +/*------------------------Export Macro Definition---------------------------*/ +/*------------------------Export Macro Definition---------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ +/* */ +/* BB and RF register read/write */ +/* */ +u32 PHY_QueryBBReg(struct rtw_adapter *Adapter, u32 RegAddr, + u32 BitMask); +void PHY_SetBBReg(struct rtw_adapter *Adapter, u32 RegAddr, + u32 BitMask, u32 Data); +u32 PHY_QueryRFReg(struct rtw_adapter *Adapter, + enum RF_RADIO_PATH eRFPath, u32 RegAddr, + u32 BitMask); +void PHY_SetRFReg(struct rtw_adapter *Adapter, + enum RF_RADIO_PATH eRFPath, u32 RegAddr, + u32 BitMask, u32 Data); + +/* */ +/* BB TX Power R/W */ +/* */ +void PHY_SetTxPowerLevel8723A(struct rtw_adapter *Adapter, u8 channel); + +/* */ +/* Switch bandwidth for 8723A */ +/* */ +void PHY_SetBWMode23a8723A(struct rtw_adapter *pAdapter, + enum ht_channel_width ChnlWidth, + unsigned char Offset); + +/* */ +/* channel switch related funciton */ +/* */ +void PHY_SwChnl8723A(struct rtw_adapter *pAdapter, u8 channel); + /* Call after initialization */ +void ChkFwCmdIoDone(struct rtw_adapter *Adapter); + +/* */ +/* Modify the value of the hw register when beacon interval be changed. */ +/* */ +void +rtl8192c_PHY_SetBeaconHwReg(struct rtw_adapter *Adapter, u16 BeaconInterval); + + +void PHY_SwitchEphyParameter(struct rtw_adapter *Adapter); + +void PHY_EnableHostClkReq(struct rtw_adapter *Adapter); + +bool +SetAntennaConfig92C(struct rtw_adapter *Adapter, u8 DefaultAnt); + +/*--------------------------Exported Function prototype---------------------*/ + +#define PHY_SetMacReg PHY_SetBBReg + +/* MAC/BB/RF HAL config */ +int PHY_BBConfig8723A(struct rtw_adapter *Adapter); +int PHY_RFConfig8723A(struct rtw_adapter *Adapter); +s32 PHY_MACConfig8723A(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyReg.h b/drivers/staging/rtl8723au/include/Hal8723APhyReg.h new file mode 100644 index 000000000000..759928f78d6d --- /dev/null +++ b/drivers/staging/rtl8723au/include/Hal8723APhyReg.h @@ -0,0 +1,1078 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __INC_HAL8723APHYREG_H__ +#define __INC_HAL8723APHYREG_H__ + +/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */ +/* 1. Page1(0x100) */ +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +/* 2. Page2(0x200) */ +/* The following two definition are only used for USB interface. */ +#define RF_BB_CMD_ADDR 0x02c0 /* RF/BB read/write command address. */ +#define RF_BB_CMD_DATA 0x02c4 /* RF/BB read/write command data. */ + +/* 3. Page8(0x800) */ +#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC RF BW Setting?? */ + +#define rFPGA0_TxInfo 0x804 /* Status report?? */ +#define rFPGA0_PSDFunction 0x808 + +#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ + +#define rFPGA0_RFTiming1 0x810 /* Useless now */ +#define rFPGA0_RFTiming2 0x814 + +#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rTxAGC_B_Rate18_06 0x830 +#define rTxAGC_B_Rate54_24 0x834 +#define rTxAGC_B_CCK1_55_Mcs32 0x838 +#define rTxAGC_B_Mcs03_Mcs00 0x83c + +#define rTxAGC_B_Mcs07_Mcs04 0x848 +#define rTxAGC_B_Mcs11_Mcs08 0x84c + +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 + +#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */ +#define rFPGA0_RFSleepUpParameter 0x854 + +#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ +#define rFPGA0_XCD_SwitchControl 0x85c + +#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ +#define rFPGA0_XB_RFInterfaceOE 0x864 + +#define rTxAGC_B_Mcs15_Mcs12 0x868 +#define rTxAGC_B_CCK11_A_CCK2_11 0x86c + +#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */ +#define rFPGA0_XCD_RFInterfaceSW 0x874 + +#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ +#define rFPGA0_XCD_RFParameter 0x87c + +#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */ +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 /* Useless now */ +#define rFPGA0_AnalogParameter4 0x88c + +#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */ +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac + +#define rFPGA0_PSDReport 0x8b4 /* Useless now */ +#define TransceiverA_HSPI_Readback 0x8b8 /* Transceiver A HSPI Readback */ +#define TransceiverB_HSPI_Readback 0x8bc /* Transceiver B HSPI Readback */ +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now RF Interface Readback Value */ +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ + +/* 4. Page9(0x900) */ +#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC RF BW Setting?? */ + +#define rFPGA1_TxBlock 0x904 /* Useless now */ +#define rFPGA1_DebugSelect 0x908 /* Useless now */ +#define rFPGA1_TxInfo 0x90c /* Useless now Status report?? */ + +/* 5. PageA(0xA00) */ +/* Set Control channel to upper or lower. These settings are required only for 40MHz */ +#define rCCK0_System 0xa00 + +#define rCCK0_AFESetting 0xa04 /* Disable init gain now Select RX path by RSSI */ +#define rCCK0_CCA 0xa08 /* Disable init gain now Init gain */ + +#define rCCK0_RxAGC1 0xa0c /* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */ +#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ + +#define rCCK0_RxHP 0xa14 + +#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel estimation threshold */ +#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ + +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ +#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */ +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 /* 0xa57 */ +#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ +#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ +/* PageB(0xB00) */ +#define rPdp_AntA 0xb00 +#define rPdp_AntA_4 0xb04 +#define rConfig_Pmpd_AntA 0xb28 +#define rConfig_AntA 0xb68 +#define rConfig_AntB 0xb6c +#define rPdp_AntB 0xb70 +#define rPdp_AntB_4 0xb74 +#define rConfig_Pmpd_AntB 0xb98 +#define rAPK 0xbd8 + +/* 6. PageC(0xC00) */ +#define rOFDM0_LSTF 0xc00 + +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c + +#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */ +#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c + +#define rOFDM0_RxDetector1 0xc30 /* PD,BW & SBD DM tune init gain */ +#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ +#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ +#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */ + +#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ +#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ +#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ +#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ + +#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c + +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c + +#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */ +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c + +#define rOFDM0_RxIQExtAnta 0xca0 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 + +/* 7. PageD(0xD00) */ +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 + +#define rOFDM1_CFO 0xd08 /* No setting now */ +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 + +#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ +#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ +#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ + +#define rOFDM_ShortCFOAB 0xdac /* No setting now */ +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + + +/* 8. PageE(0xE00) */ +#define rTxAGC_A_Rate18_06 0xe00 +#define rTxAGC_A_Rate54_24 0xe04 +#define rTxAGC_A_CCK1_Mcs32 0xe08 +#define rTxAGC_A_Mcs03_Mcs00 0xe10 +#define rTxAGC_A_Mcs07_Mcs04 0xe14 +#define rTxAGC_A_Mcs11_Mcs08 0xe18 +#define rTxAGC_A_Mcs15_Mcs12 0xe1c + +#define rFPGA0_IQK 0xe28 +#define rTx_IQK_Tone_A 0xe30 +#define rRx_IQK_Tone_A 0xe34 +#define rTx_IQK_PI_A 0xe38 +#define rRx_IQK_PI_A 0xe3c + +#define rTx_IQK 0xe40 +#define rRx_IQK 0xe44 +#define rIQK_AGC_Pts 0xe48 +#define rIQK_AGC_Rsp 0xe4c +#define rTx_IQK_Tone_B 0xe50 +#define rRx_IQK_Tone_B 0xe54 +#define rTx_IQK_PI_B 0xe58 +#define rRx_IQK_PI_B 0xe5c +#define rIQK_AGC_Cont 0xe60 + +#define rBlue_Tooth 0xe6c +#define rRx_Wait_CCA 0xe70 +#define rTx_CCK_RFON 0xe74 +#define rTx_CCK_BBON 0xe78 +#define rTx_OFDM_RFON 0xe7c +#define rTx_OFDM_BBON 0xe80 +#define rTx_To_Rx 0xe84 +#define rTx_To_Tx 0xe88 +#define rRx_CCK 0xe8c + +#define rTx_Power_Before_IQK_A 0xe94 +#define rTx_Power_After_IQK_A 0xe9c + +#define rRx_Power_Before_IQK_A 0xea0 +#define rRx_Power_Before_IQK_A_2 0xea4 +#define rRx_Power_After_IQK_A 0xea8 +#define rRx_Power_After_IQK_A_2 0xeac + +#define rTx_Power_Before_IQK_B 0xeb4 +#define rTx_Power_After_IQK_B 0xebc + +#define rRx_Power_Before_IQK_B 0xec0 +#define rRx_Power_Before_IQK_B_2 0xec4 +#define rRx_Power_After_IQK_B 0xec8 +#define rRx_Power_After_IQK_B_2 0xecc + +#define rRx_OFDM 0xed0 +#define rRx_Wait_RIFS 0xed4 +#define rRx_TO_Rx 0xed8 +#define rStandby 0xedc +#define rSleep 0xee0 +#define rPMPD_ANAEN 0xeec + +/* 7. RF Register 0x00-0x2E (RF 8256) */ +/* RF-0222D 0x00-3F */ +/* Zebra1 */ +#define rZebra1_HSSIEnable 0x0 /* Useless now */ +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +#define rZebra1_Channel 0x7 /* RF channel switch */ + +#define rZebra1_TxGain 0x8 /* Useless now */ +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +/* Zebra4 */ +#define rGlobalCtrl 0 /* Useless now */ +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +/* RTL8258 */ +#define rRTL8258_TxLPF 0x11 /* Useless now */ +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +/* RL6052 Register definition */ +#define RF_AC 0x00 +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_BS_PA_APSET_G1_G4 0x03 +#define RF_BS_PA_APSET_G5_G8 0x04 +#define RF_POW_TRSW 0x05 +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 +#define RF_TXM_IDAC 0x08 +#define RF_IPA_G 0x09 +#define RF_TXBIAS_G 0x0A +#define RF_TXPA_AG 0x0B +#define RF_IPA_A 0x0C +#define RF_TXBIAS_A 0x0D +#define RF_BS_PA_APSET_G9_G11 0x0E +#define RF_BS_IQGEN 0x0F +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_TXBIAS 0x16 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define rRfChannel 0x18 /* RF channel and BW switch */ +#define RF_CHNLBW 0x18 /* RF channel and BW switch */ +#define RF_TOP 0x19 +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x24 +#define RF_SYN_G1 0x25 /* RF TX Power control */ +#define RF_SYN_G2 0x26 /* RF TX Power control */ +#define RF_SYN_G3 0x27 /* RF TX Power control */ +#define RF_SYN_G4 0x28 /* RF TX Power control */ +#define RF_SYN_G5 0x29 /* RF TX Power control */ +#define RF_SYN_G6 0x2A /* RF TX Power control */ +#define RF_SYN_G7 0x2B /* RF TX Power control */ +#define RF_SYN_G8 0x2C /* RF TX Power control */ + +#define RF_RCK_OS 0x30 /* RF TX PA control */ + +#define RF_TXPA_G1 0x31 /* RF TX PA control */ +#define RF_TXPA_G2 0x32 /* RF TX PA control */ +#define RF_TXPA_G3 0x33 /* RF TX PA control */ + +/* Bit Mask */ +/* 1. Page1(0x100) */ +#define bBBResetB 0x100 /* Useless now? */ +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 + +#define IS_BB_REG_OFFSET_92S(_Offset) \ + ((_Offset >= 0x800) && (_Offset <= 0xfff)) + +/* 2. Page8(0x800) */ +#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 + +#define bOFDMRxADCPhase 0x10000 /* Useless now */ +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f + +#define bAntennaSelect 0x0300 + +#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 + +#define bPAStart 0xf0000000 /* Useless now */ +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +#define bPAEnd 0xf /* Reg0x814 */ +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +#define bCCAMask 0x000000f0 /* T2R */ +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +#define bContTxHSSI 0x400 /* chane gain at continue Tx */ +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 + +#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */ +#define b3WireAddressLength 0x400 + +#define b3WireRFPowerDown 0x1 /* Useless now */ +/* define bHWSISelect 0x8 */ +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +#define bRFSI_3Wire 0xf + +#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ + +#define bRFSI_TRSW 0x20 /* Useless now */ +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 + +#define bLSSIReadAddress 0x7f800000 /* T65 RF */ + +#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ + +#define bLSSIReadBackData 0xfffff /* T65 RF */ + +#define bLSSIReadOKFlag 0x1000 /* Useless now */ +#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */ +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 + +#define bADClkPhase 0x4000000 /* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ + +#define b80MClkDelay 0x18000000 /* Useless */ +#define bAFEWatchDogEnable 0x20000000 + +#define bXtalCap01 0xc0000000 /* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */ +#define bXtalCap23 0x3 +#define bXtalCap92x 0x0f000000 +#define bXtalCap 0x0f000000 + +#define bIntDifClkEnable 0x400 /* Useless */ +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 +#define bCCKRxAGCFormat 0x200 +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +/* 3. Page9(0x900) */ +#define bOFDMTxSC 0x30000000 /* Useless */ +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +#define bDebugPage 0xfff /* reset debug page and also HWord, LWord */ +#define bDebugItem 0xff /* reset debug page and LWord */ +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +/* 4. PageA(0xA00) */ +#define bCCKBBMode 0x3 /* Useless */ +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 + +#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch */ + +#define bCCKScramble 0x8 /* Useless */ +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ +#define bCCKFixedRxAGC 0x8000 +/* define bCCKRxAGCFormat 0x4000 remove to HSSI register 0x824 */ +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +/* 5. PageC(0xC00) */ +#define bNumOfSTF 0x3 /* Useless */ +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +#define bRSSI_H 0x7f0000 /* the threshold for high power */ +#define bRSSI_Gen 0x7f000000 /* the threshold for ant diversity */ +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +/* define bRxMF_Hold 0x3800 */ +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 +#define bDAFormat 0x40000 +#define bTxChEmuEnable 0x01000000 +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 +#define bExtLNAGain 0x7c00 + +/* 6. PageE(0xE00) */ +#define bSTBCEn 0x4 /* Useless */ +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +/* define bRxPath1 0x01 */ +/* define bRxPath2 0x02 */ +/* define bRxPath3 0x04 */ +/* define bRxPath4 0x08 */ +/* define bTxPath1 0x10 */ +/* define bTxPath2 0x20 */ +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +#define bShortCFOTLength 12 /* total */ +#define bShortCFOFLength 11 /* fraction */ +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf /* Useless */ +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 /* Useless */ +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 /* Useless */ +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +/* Rx Pseduo noise */ +#define bRxPesudoNoiseOn 0x20000000 /* Useless */ +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +/* 7. RF Register */ +/* Zebra1 */ +#define bZebra1_HSSIEnable 0x8 /* Useless */ +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +/* Zebra4 */ +#define bRTL8256RegModeCtrl1 0x100 /* Useless */ +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +/* RTL8258 */ +#define bRTL8258_TxLPFBW 0xc /* Useless */ +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + + +/* Other Definition */ + +/* byte endable for sb_write */ +#define bByte0 0x1 /* Useless */ +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +/* for PutRegsetting & GetRegSetting BitMask */ +#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff +#define bMask12Bits 0xfff +#define bMaskH4Bits 0xf0000000 +#define bMaskOFDM_D 0xffc00000 +#define bMaskCCK 0x3f3f3f3f + +/* for PutRFRegsetting & GetRFRegSetting BitMask */ +#define bRFRegOffsetMask 0xfffff + +#define bDisable 0x0 + +#define LeftAntenna 0x0 /* Useless */ +#define RightAntenna 0x1 + +#define tCheckTxStatus 500 /* 500ms Useless */ +#define tUpdateRxCounter 100 /* 100ms */ + +#define rateCCK 0 /* Useless */ +#define rateOFDM 1 +#define rateHT 2 + +/* define Register-End */ +#define bPMAC_End 0x1ff /* Useless */ +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + +/* define max debug item in each debug page */ +/* define bMaxItem_FPGA_PHY0 0x9 */ +/* define bMaxItem_FPGA_PHY1 0x3 */ +/* define bMaxItem_PHY_11B 0x16 */ +/* define bMaxItem_OFDM_PHY0 0x29 */ +/* define bMaxItem_OFDM_PHY1 0x0 */ + +#define bPMACControl 0x0 /* Useless */ +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define PathA 0x0 /* Useless */ +#define PathB 0x1 +#define PathC 0x2 +#define PathD 0x3 + +/* PageB(0xB00) */ +#define rPdp_AntA 0xb00 +#define rPdp_AntA_4 0xb04 +#define rPdp_AntA_8 0xb08 +#define rPdp_AntA_C 0xb0c +#define rPdp_AntA_18 0xb18 +#define rPdp_AntA_1C 0xb1c +#define rPdp_AntA_20 0xb20 +#define rPdp_AntA_24 0xb24 + +#define rConfig_Pmpd_AntA 0xb28 +#define rConfig_ram64x16 0xb2c + +#define rBndA 0xb30 +#define rHssiPar 0xb34 + +#define rConfig_AntA 0xb68 +#define rConfig_AntB 0xb6c + +#define rPdp_AntB 0xb70 +#define rPdp_AntB_4 0xb74 +#define rPdp_AntB_8 0xb78 +#define rPdp_AntB_C 0xb7c +#define rPdp_AntB_10 0xb80 +#define rPdp_AntB_14 0xb84 +#define rPdp_AntB_18 0xb88 +#define rPdp_AntB_1C 0xb8c +#define rPdp_AntB_20 0xb90 +#define rPdp_AntB_24 0xb94 + +#define rConfig_Pmpd_AntB 0xb98 + +#define rBndB 0xba0 + +#define rAPK 0xbd8 +#define rPm_Rx0_AntA 0xbdc +#define rPm_Rx1_AntA 0xbe0 +#define rPm_Rx2_AntA 0xbe4 +#define rPm_Rx3_AntA 0xbe8 +#define rPm_Rx0_AntB 0xbec +#define rPm_Rx1_AntB 0xbf0 +#define rPm_Rx2_AntB 0xbf4 +#define rPm_Rx3_AntB 0xbf8 + +#endif diff --git a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h new file mode 100644 index 000000000000..7f3bdea6a55e --- /dev/null +++ b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h @@ -0,0 +1,150 @@ +#ifndef __HAL8723PWRSEQ_H__ +#define __HAL8723PWRSEQ_H__ +/* + Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd + There are 6 HW Power States: + 0: POFF--Power Off + 1: PDN--Power Down + 2: CARDEMU--Card Emulation + 3: ACT--Active Mode + 4: LPS--Low Power State + 5: SUS--Suspend + + The transision from different states are defined below + TRANS_CARDEMU_TO_ACT + TRANS_ACT_TO_CARDEMU + TRANS_CARDEMU_TO_SUS + TRANS_SUS_TO_CARDEMU + TRANS_CARDEMU_TO_PDN + TRANS_ACT_TO_LPS + TRANS_LPS_TO_ACT + + TRANS_END +*/ +#include "HalPwrSeqCmd.h" +#include "rtl8723a_spec.h" + +#define RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS 15 +#define RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS 15 +#define RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS 15 +#define RTL8723A_TRANS_SUS_TO_CARDEMU_STEPS 15 +#define RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS 15 +#define RTL8723A_TRANS_PDN_TO_CARDEMU_STEPS 15 +#define RTL8723A_TRANS_ACT_TO_LPS_STEPS 15 +#define RTL8723A_TRANS_LPS_TO_ACT_STEPS 15 +#define RTL8723A_TRANS_END_STEPS 1 + + +/* format + * { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here + */ +#define RTL8723A_TRANS_CARDEMU_TO_ACT \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \ + {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \ + {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]= 0*/ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset 0x04[16]= 1*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]= 0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/ \ + {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 1},/*0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */\ + +#define RTL8723A_TRANS_ACT_TO_CARDEMU \ + {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \ + {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */\ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/ \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \ + + +#define RTL8723A_TRANS_CARDEMU_TO_SUS \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ + +#define RTL8723A_TRANS_SUS_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ + +#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/ \ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/ + +#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/ + + +#define RTL8723A_TRANS_CARDEMU_TO_PDN \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/ + +#define RTL8723A_TRANS_PDN_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/ + +#define RTL8723A_TRANS_ACT_TO_LPS \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \ + {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/ \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \ + {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \ + {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ + +#define RTL8723A_TRANS_LPS_TO_ACT \ + {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\ + {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\ + {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\ + {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]= 0 TSF in 40M*/\ + {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/ + +#define RTL8723A_TRANS_END \ + {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0}, + + +extern struct wlan_pwr_cfg rtl8723AU_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STEPS+RTL8723A_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723AU_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS]; + +#endif diff --git a/drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h b/drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h new file mode 100644 index 000000000000..bbeaab48057a --- /dev/null +++ b/drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h @@ -0,0 +1,29 @@ +#ifndef __INC_HAL8723U_FW_IMG_H +#define __INC_HAL8723U_FW_IMG_H + +/*Created on 2013/01/14, 15:51*/ + +/* FW v16 enable usb interrupt */ +#define Rtl8723UImgArrayLength 22172 +extern u8 Rtl8723UFwImgArray[Rtl8723UImgArrayLength]; +#define Rtl8723UBTImgArrayLength 1 +extern u8 Rtl8723UFwBTImgArray[Rtl8723UBTImgArrayLength]; + +#define Rtl8723UUMCBCutImgArrayWithBTLength 24118 +#define Rtl8723UUMCBCutImgArrayWithoutBTLength 19200 + +extern u8 Rtl8723UFwUMCBCutImgArrayWithBT[Rtl8723UUMCBCutImgArrayWithBTLength]; +extern u8 Rtl8723UFwUMCBCutImgArrayWithoutBT[Rtl8723UUMCBCutImgArrayWithoutBTLength]; + +#define Rtl8723SUMCBCutMPImgArrayLength 24174 +extern const u8 Rtl8723SFwUMCBCutMPImgArray[Rtl8723SUMCBCutMPImgArrayLength]; + +#define Rtl8723EBTImgArrayLength 15276 +extern u8 Rtl8723EFwBTImgArray[Rtl8723EBTImgArrayLength] ; + +#define Rtl8723UPHY_REG_Array_PGLength 336 +extern u32 Rtl8723UPHY_REG_Array_PG[Rtl8723UPHY_REG_Array_PGLength]; +#define Rtl8723UMACPHY_Array_PGLength 1 +extern u32 Rtl8723UMACPHY_Array_PG[Rtl8723UMACPHY_Array_PGLength]; + +#endif /* ifndef __INC_HAL8723U_FW_IMG_H */ diff --git a/drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h b/drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h new file mode 100644 index 000000000000..d7651f7a665b --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __RTL8723A_ODM_H__ +#define __RTL8723A_ODM_H__ +/* */ + +#define RSSI_CCK 0 +#define RSSI_OFDM 1 +#define RSSI_DEFAULT 2 + +#define IQK_MAC_REG_NUM 4 +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 9 +#define HP_THERMAL_NUM 8 + + +/* */ +/* structure and define */ +/* */ + + + + +/*------------------------Export global variable----------------------------*/ +/*------------------------Export global variable----------------------------*/ +/*------------------------Export Marco Definition---------------------------*/ +/* define DM_MultiSTA_InitGainChangeNotify(Event) {DM_DigTable.CurMultiSTAConnectState = Event;} */ + + +/* */ +/* function prototype */ +/* */ + +/* */ +/* IQ calibrate */ +/* */ +void rtl8723a_phy_iq_calibrate(struct rtw_adapter *pAdapter, bool bReCovery); + +/* */ +/* LC calibrate */ +/* */ +void rtl8723a_phy_lc_calibrate(struct rtw_adapter *pAdapter); + +/* */ +/* AP calibrate */ +/* */ +void rtl8723a_phy_ap_calibrate(struct rtw_adapter *pAdapter, char delta); + +void rtl8723a_odm_check_tx_power_tracking(struct rtw_adapter *Adapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h new file mode 100644 index 000000000000..e99833cc7929 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h @@ -0,0 +1,44 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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. +* +* +******************************************************************************/ + +#ifndef __INC_BB_8723A_HW_IMG_H +#define __INC_BB_8723A_HW_IMG_H + +/****************************************************************************** +* AGC_TAB_1T.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_AGC_TAB_1T_8723A(struct dm_odm_t *pDM_Odm); + +/****************************************************************************** +* PHY_REG_1T.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_PHY_REG_1T_8723A(struct dm_odm_t *pDM_Odm); + +/****************************************************************************** +* PHY_REG_MP.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_PHY_REG_MP_8723A(struct dm_odm_t *pDM_Odm); + +/****************************************************************************** +* PHY_REG_PG.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm); + +#endif /* end of HWIMG_SUPPORT */ diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h new file mode 100644 index 000000000000..7ee363b99b49 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h @@ -0,0 +1,28 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. +* +* 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. +* +* +******************************************************************************/ + +#ifndef __INC_FW_8723A_HW_IMG_H +#define __INC_FW_8723A_HW_IMG_H + + +/****************************************************************************** +* rtl8723fw_B.TXT +******************************************************************************/ + +void ODM_ReadFirmware_8723A_rtl8723fw_B(struct dm_odm_t *pDM_Odm, + u8 *pFirmware, u32 *pFirmwareSize); + +#endif /* end of HWIMG_SUPPORT */ diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h new file mode 100644 index 000000000000..201be1f87292 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h @@ -0,0 +1,26 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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. +* +* +******************************************************************************/ + +#ifndef __INC_MAC_8723A_HW_IMG_H +#define __INC_MAC_8723A_HW_IMG_H + +/****************************************************************************** +* MAC_REG.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_MAC_REG_8723A(struct dm_odm_t *pDM_Odm); + +#endif /* end of HWIMG_SUPPORT */ diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h new file mode 100644 index 000000000000..c9af1c375339 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h @@ -0,0 +1,25 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* 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. +* +******************************************************************************/ + +#ifndef __INC_RF_8723A_HW_IMG_H +#define __INC_RF_8723A_HW_IMG_H + +/****************************************************************************** +* RadioA_1T.TXT +******************************************************************************/ + +void ODM_ReadAndConfig_RadioA_1T_8723A(struct dm_odm_t *pDM_Odm); + +#endif /* end of HWIMG_SUPPORT */ diff --git a/drivers/staging/rtl8723au/include/HalPwrSeqCmd.h b/drivers/staging/rtl8723au/include/HalPwrSeqCmd.h new file mode 100644 index 000000000000..12e03a36f2d3 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalPwrSeqCmd.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __HALPWRSEQCMD_H__ +#define __HALPWRSEQCMD_H__ + +#include + +/*---------------------------------------------*/ +/*---------------------------------------------*/ +#define PWR_CMD_READ 0x00 + /* offset: the read register offset */ + /* msk: the mask of the read value */ + /* value: N/A, left by 0 */ + /* note: dirver shall implement this function by read & msk */ + +#define PWR_CMD_WRITE 0x01 + /* offset: the read register offset */ + /* msk: the mask of the write bits */ + /* value: write value */ + /* note: driver shall implement this cmd by read & msk after write */ + +#define PWR_CMD_POLLING 0x02 + /* offset: the read register offset */ + /* msk: the mask of the polled value */ + /* value: the value to be polled, masked by the msd field. */ + /* note: driver shall implement this cmd by */ + /* do{ */ + /* if( (Read(offset) & msk) == (value & msk) ) */ + /* break; */ + /* } while(not timeout); */ + +#define PWR_CMD_DELAY 0x03 + /* offset: the value to delay */ + /* msk: N/A */ + /* value: the unit of delay, 0: us, 1: ms */ + +#define PWR_CMD_END 0x04 + /* offset: N/A */ + /* msk: N/A */ + /* value: N/A */ + +/*---------------------------------------------*/ +/* 3 The value of base: 4 bits */ +/*---------------------------------------------*/ + /* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +/*---------------------------------------------*/ +/* 3 The value of interface_msk: 4 bits */ +/*---------------------------------------------*/ +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +/*---------------------------------------------*/ +/* 3 The value of fab_msk: 4 bits */ +/*---------------------------------------------*/ +#define PWR_FAB_TSMC_MSK BIT(0) +#define PWR_FAB_UMC_MSK BIT(1) +#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +/*---------------------------------------------*/ +/* 3 The value of cut_msk: 8 bits */ +/*---------------------------------------------*/ +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF + + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; +}; + + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk +#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base +#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd +#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk +#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value + + +/* */ +/* Prototype of protected function. */ +/* */ +u8 HalPwrSeqCmdParsing23a( + struct rtw_adapter *padapter, + u8 CutVersion, + u8 FabVersion, + u8 InterfaceType, + struct wlan_pwr_cfg PwrCfgCmd[]); + +#endif diff --git a/drivers/staging/rtl8723au/include/HalVerDef.h b/drivers/staging/rtl8723au/include/HalVerDef.h new file mode 100644 index 000000000000..607b71f6e1e4 --- /dev/null +++ b/drivers/staging/rtl8723au/include/HalVerDef.h @@ -0,0 +1,136 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __HAL_VERSION_DEF_H__ +#define __HAL_VERSION_DEF_H__ + +enum hal_ic_type { + CHIP_8192S = 0, + CHIP_8188C = 1, + CHIP_8192C = 2, + CHIP_8192D = 3, + CHIP_8723A = 4, + CHIP_8188E = 5, + CHIP_8881A = 6, + CHIP_8812A = 7, + CHIP_8821A = 8, + CHIP_8723B = 9, + CHIP_8192E = 10, +}; + +enum hal_chip_type { + TEST_CHIP = 0, + NORMAL_CHIP = 1, + FPGA = 2, +}; + +enum hal_cut_version { + A_CUT_VERSION = 0, + B_CUT_VERSION = 1, + C_CUT_VERSION = 2, + D_CUT_VERSION = 3, + E_CUT_VERSION = 4, + F_CUT_VERSION = 5, + G_CUT_VERSION = 6, +}; + +/* HAL_Manufacturer */ +enum hal_vendor { + CHIP_VENDOR_TSMC = 0, + CHIP_VENDOR_UMC = 1, +}; + +enum hal_rf_type { + RF_TYPE_1T1R = 0, + RF_TYPE_1T2R = 1, + RF_TYPE_2T2R = 2, + RF_TYPE_2T3R = 3, + RF_TYPE_2T4R = 4, + RF_TYPE_3T3R = 5, + RF_TYPE_3T4R = 6, + RF_TYPE_4T4R = 7, +}; + +struct hal_version { + enum hal_ic_type ICType; + enum hal_chip_type ChipType; + enum hal_cut_version CUTVersion; + enum hal_vendor VendorType; + enum hal_rf_type RFType; + u8 ROMVer; +}; + +/* Get element */ +#define GET_CVID_IC_TYPE(version) ((version).ICType) +#define GET_CVID_CHIP_TYPE(version) ((version).ChipType) +#define GET_CVID_RF_TYPE(version) ((version).RFType) +#define GET_CVID_MANUFACTUER(version) ((version).VendorType) +#define GET_CVID_CUT_VERSION(version) ((version).CUTVersion) +#define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) + +/* Common Macro. -- */ + +#define IS_81XXC(version) \ + (((GET_CVID_IC_TYPE(version) == CHIP_8192C) || \ + (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? true : false) +#define IS_8723_SERIES(version) \ + ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? true : false) + +#define IS_TEST_CHIP(version) \ + ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false) +#define IS_NORMAL_CHIP(version) \ + ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false) + +#define IS_A_CUT(version) \ + ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false) +#define IS_B_CUT(version) \ + ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false) +#define IS_C_CUT(version) \ + ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false) +#define IS_D_CUT(version) \ + ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false) +#define IS_E_CUT(version) \ + ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false) + +#define IS_CHIP_VENDOR_TSMC(version) \ + ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false) +#define IS_CHIP_VENDOR_UMC(version) \ + ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false) + +#define IS_1T1R(version) \ + ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false) +#define IS_1T2R(version) \ + ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false) +#define IS_2T2R(version) \ + ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false) + +/* Chip version Macro. -- */ + +#define IS_92C_SERIAL(version) \ + ((IS_81XXC(version) && IS_2T2R(version)) ? true : false) +#define IS_81xxC_VENDOR_UMC_A_CUT(version) \ + (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ? \ + (IS_A_CUT(version) ? true : false) : false) : false) +#define IS_81xxC_VENDOR_UMC_B_CUT(version) \ + (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \ + (IS_B_CUT(version) ? true : false) : false): false) +#define IS_81xxC_VENDOR_UMC_C_CUT(version) \ + (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ? \ + (IS_C_CUT(version) ? true : false) : false) : false) +#define IS_8723A_A_CUT(version) \ + ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? true : false) : false) +#define IS_8723A_B_CUT(version) \ + ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? true : false) : false) + +#endif diff --git a/drivers/staging/rtl8723au/include/cmd_osdep.h b/drivers/staging/rtl8723au/include/cmd_osdep.h new file mode 100644 index 000000000000..4866bee04054 --- /dev/null +++ b/drivers/staging/rtl8723au/include/cmd_osdep.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __CMD_OSDEP_H_ +#define __CMD_OSDEP_H_ + +#include +#include + +int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv); +void _rtw_free_evt_priv23a(struct evt_priv *pevtpriv); +void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv); +int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj); + +#endif diff --git a/drivers/staging/rtl8723au/include/drv_types.h b/drivers/staging/rtl8723au/include/drv_types.h new file mode 100644 index 000000000000..58479884254a --- /dev/null +++ b/drivers/staging/rtl8723au/include/drv_types.h @@ -0,0 +1,364 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/*----------------------------------------------------------------------------- + + For type defines and data structure defines + +------------------------------------------------------------------------------*/ + + +#ifndef __DRV_TYPES_H__ +#define __DRV_TYPES_H__ + +#include +#include + + +enum _NIC_VERSION { + RTL8711_NIC, + RTL8712_NIC, + RTL8713_NIC, + RTL8716_NIC + +}; + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ioctl_cfg80211.h" + +#define SPEC_DEV_ID_NONE BIT(0) +#define SPEC_DEV_ID_DISABLE_HT BIT(1) +#define SPEC_DEV_ID_ENABLE_PS BIT(2) +#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3) +#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) +#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) + +struct specific_device_id { + u32 flags; + + u16 idVendor; + u16 idProduct; + +}; + +struct registry_priv { + u8 chip_version; + u8 rfintfs; + struct cfg80211_ssid ssid; + u8 channel;/* ad-hoc support requirement */ + u8 wireless_mode;/* A, B, G, auto */ + u8 scan_mode;/* active, passive */ + u8 preamble;/* long, short, auto */ + u8 vrtl_carrier_sense;/* Enable, Disable, Auto */ + u8 vcs_type;/* RTS/CTS, CTS-to-self */ + u16 rts_thresh; + u16 frag_thresh; + u8 adhoc_tx_pwr; + u8 soft_ap; + u8 power_mgnt; + u8 ips_mode; + u8 smart_ps; + u8 long_retry_lmt; + u8 short_retry_lmt; + u16 busy_thresh; + u8 ack_policy; + u8 software_encrypt; + u8 software_decrypt; + u8 acm_method; + /* UAPSD */ + u8 wmm_enable; + u8 uapsd_enable; + + struct wlan_bssid_ex dev_network; + + u8 ht_enable; + u8 cbw40_enable; + u8 ampdu_enable;/* for tx */ + u8 rx_stbc; + u8 ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */ + u8 lowrate_two_xmit; + + u8 rf_config; + u8 low_power; + + u8 wifi_spec;/* !turbo_mode */ + + u8 channel_plan; +#ifdef CONFIG_8723AU_BT_COEXIST + u8 btcoex; + u8 bt_iso; + u8 bt_sco; + u8 bt_ampdu; +#endif + bool bAcceptAddbaReq; + + u8 antdiv_cfg; + u8 antdiv_type; + + u8 usbss_enable;/* 0:disable,1:enable */ + u8 hwpdn_mode;/* 0:disable,1:enable,2:decide by EFUSE config */ + u8 hwpwrp_detect;/* 0:disable,1:enable */ + + u8 hw_wps_pbc;/* 0:disable,1:enable */ + + u8 max_roaming_times; /* max number driver will try to roaming */ + + u8 enable80211d; + + u8 ifname[16]; + u8 if2name[16]; + + u8 notch_filter; + + u8 regulatory_tid; +}; + + +#define MAX_CONTINUAL_URB_ERR 4 + +#define GET_PRIMARY_ADAPTER(padapter) \ + (((struct rtw_adapter *)padapter)->dvobj->if1) + +enum _IFACE_ID { + IFACE_ID0, /* maping to PRIMARY_ADAPTER */ + IFACE_ID1, /* maping to SECONDARY_ADAPTER */ + IFACE_ID2, + IFACE_ID3, + IFACE_ID_MAX, +}; + +struct dvobj_priv { + struct rtw_adapter *if1; /* PRIMARY_ADAPTER */ + struct rtw_adapter *if2; /* SECONDARY_ADAPTER */ + + /* for local/global synchronization */ + struct mutex hw_init_mutex; + struct mutex h2c_fwcmd_mutex; + struct mutex setch_mutex; + struct mutex setbw_mutex; + + unsigned char oper_channel; /* saved chan info when set chan bw */ + unsigned char oper_bwmode; + unsigned char oper_ch_offset;/* PRIME_CHNL_OFFSET */ + + struct rtw_adapter *padapters[IFACE_ID_MAX]; + u8 iface_nums; /* total number of ifaces used runtime */ + + /* For 92D, DMDP have 2 interface. */ + u8 InterfaceNumber; + u8 NumInterfaces; + + /* In /Out Pipe information */ + int RtInPipe[2]; + int RtOutPipe[3]; + u8 Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */ + + u8 irq_alloc; + +/*-------- below is for USB INTERFACE --------*/ + + u8 nr_endpoint; + u8 ishighspeed; + u8 RtNumInPipes; + u8 RtNumOutPipes; + int ep_num[5]; /* endpoint number */ + + int RegUsbSS; + + struct semaphore usb_suspend_sema; + + struct mutex usb_vendor_req_mutex; + + u8 *usb_alloc_vendor_req_buf; + u8 *usb_vendor_req_buf; + + struct usb_interface *pusbintf; + struct usb_device *pusbdev; + atomic_t continual_urb_error; + +/*-------- below is for PCIE INTERFACE --------*/ + +}; + +static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) +{ + /* todo: get interface type from dvobj and the return the dev accordingly */ + return &dvobj->pusbintf->dev; +} + +enum _IFACE_TYPE { + IFACE_PORT0, /* mapping to port0 for C/D series chips */ + IFACE_PORT1, /* mapping to port1 for C/D series chip */ + MAX_IFACE_PORT, +}; + +enum _ADAPTER_TYPE { + PRIMARY_ADAPTER, + SECONDARY_ADAPTER, + MAX_ADAPTER, +}; + +struct rtw_adapter { + int pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */ + int bDongle;/* build-in module or external dongle */ + u16 chip_type; + u16 HardwareType; + + struct dvobj_priv *dvobj; + struct mlme_priv mlmepriv; + struct mlme_ext_priv mlmeextpriv; + struct cmd_priv cmdpriv; + struct evt_priv evtpriv; + /* struct io_queue *pio_queue; */ + struct io_priv iopriv; + struct xmit_priv xmitpriv; + struct recv_priv recvpriv; + struct sta_priv stapriv; + struct security_priv securitypriv; + struct registry_priv registrypriv; + struct pwrctrl_priv pwrctrlpriv; + struct eeprom_priv eeprompriv; + struct led_priv ledpriv; + +#ifdef CONFIG_8723AU_AP_MODE + struct hostapd_priv *phostapdpriv; +#endif + +#ifdef CONFIG_8723AU_P2P + struct cfg80211_wifidirect_info cfg80211_wdinfo; +#endif /* CONFIG_8723AU_P2P */ + u32 setband; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info wdinfo; +#endif /* CONFIG_8723AU_P2P */ + +#ifdef CONFIG_8723AU_P2P + struct wifi_display_info wfd_info; +#endif /* CONFIG_8723AU_P2P */ + + void *HalData; + u32 hal_data_sz; + struct hal_ops HalFunc; + + s32 bDriverStopped; + s32 bSurpriseRemoved; + s32 bCardDisableWOHSM; + + u32 IsrContent; + u32 ImrContent; + + u8 EepromAddressSize; + u8 hw_init_completed; + u8 bDriverIsGoingToUnload; + u8 init_adpt_in_progress; + u8 bHaltInProgress; + + void *cmdThread; + void *evtThread; + void *xmitThread; + void *recvThread; + + void (*intf_start)(struct rtw_adapter *adapter); + void (*intf_stop)(struct rtw_adapter *adapter); + + struct net_device *pnetdev; + + /* used by rtw_rereg_nd_name related function */ + struct rereg_nd_name_data { + struct net_device *old_pnetdev; + char old_ifname[IFNAMSIZ]; + u8 old_ips_mode; + u8 old_bRegUseLed; + } rereg_nd_name_priv; + + int bup; + struct net_device_stats stats; + struct iw_statistics iwstats; + struct proc_dir_entry *dir_dev;/* for proc directory */ + + struct wireless_dev *rtw_wdev; + int net_closed; + + u8 bFWReady; + u8 bBTFWReady; + u8 bReadPortCancel; + u8 bWritePortCancel; + u8 bRxRSSIDisplay; + /* The driver will show the desired chan nor when this flag is 1. */ + u8 bNotifyChannelChange; +#ifdef CONFIG_8723AU_P2P + /* driver will show current P2P status when the application reads it*/ + u8 bShowGetP2PState; +#endif + struct rtw_adapter *pbuddy_adapter; + + /* extend to support multi interface */ + /* IFACE_ID0 is equals to PRIMARY_ADAPTER */ + /* IFACE_ID1 is equals to SECONDARY_ADAPTER */ + u8 iface_id; + +#ifdef CONFIG_BR_EXT + _lock br_ext_lock; + /* unsigned int macclone_completed; */ + struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE]; + int pppoe_connection_in_progress; + unsigned char pppoe_addr[MACADDRLEN]; + unsigned char scdb_mac[MACADDRLEN]; + unsigned char scdb_ip[4]; + struct nat25_network_db_entry *scdb_entry; + unsigned char br_mac[MACADDRLEN]; + unsigned char br_ip[4]; + + struct br_ext_info ethBrExtInfo; +#endif /* CONFIG_BR_EXT */ + + u8 fix_rate; + + unsigned char in_cta_test; + +}; + +#define adapter_to_dvobj(adapter) (adapter->dvobj) + +int rtw_handle_dualmac23a(struct rtw_adapter *adapter, bool init); + +static inline u8 *myid(struct eeprom_priv *peepriv) +{ + return peepriv->mac_addr; +} + +#endif /* __DRV_TYPES_H__ */ diff --git a/drivers/staging/rtl8723au/include/ethernet.h b/drivers/staging/rtl8723au/include/ethernet.h new file mode 100644 index 000000000000..39fc6df88188 --- /dev/null +++ b/drivers/staging/rtl8723au/include/ethernet.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +/*! \file */ +#ifndef __INC_ETHERNET_H +#define __INC_ETHERNET_H + +#define LLC_HEADER_SIZE 6 /* LLC Header Length */ + +#endif /* #ifndef __INC_ETHERNET_H */ diff --git a/drivers/staging/rtl8723au/include/hal_com.h b/drivers/staging/rtl8723au/include/hal_com.h new file mode 100644 index 000000000000..20f983cfc2b7 --- /dev/null +++ b/drivers/staging/rtl8723au/include/hal_com.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __HAL_COMMON_H__ +#define __HAL_COMMON_H__ + +/* */ +/* Rate Definition */ +/* */ +/* CCK */ +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +/* OFDM */ +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +/* MCS 1 Spatial Stream */ +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +/* MCS 2 Spatial Stream */ +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +/* CCK */ +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +/* OFDM */ +#define RATE_6M BIT(4) +#define RATE_9M BIT(5) +#define RATE_12M BIT(6) +#define RATE_18M BIT(7) +#define RATE_24M BIT(8) +#define RATE_36M BIT(9) +#define RATE_48M BIT(10) +#define RATE_54M BIT(11) +/* MCS 1 Spatial Stream */ +#define RATE_MCS0 BIT(12) +#define RATE_MCS1 BIT(13) +#define RATE_MCS2 BIT(14) +#define RATE_MCS3 BIT(15) +#define RATE_MCS4 BIT(16) +#define RATE_MCS5 BIT(17) +#define RATE_MCS6 BIT(18) +#define RATE_MCS7 BIT(19) +/* MCS 2 Spatial Stream */ +#define RATE_MCS8 BIT(20) +#define RATE_MCS9 BIT(21) +#define RATE_MCS10 BIT(22) +#define RATE_MCS11 BIT(23) +#define RATE_MCS12 BIT(24) +#define RATE_MCS13 BIT(25) +#define RATE_MCS14 BIT(26) +#define RATE_MCS15 BIT(27) + +/* ALL CCK Rate */ +#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG \ + (RATR_6M | RATR_9M | RATR_12M | RATR_18M | RATR_24M| \ + RATR_36M|RATR_48M|RATR_54M) +#define RATE_ALL_OFDM_1SS \ + (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | RATR_MCS3 | \ + RATR_MCS4 | RATR_MCS5 | RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS \ + (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | RATR_MCS11| \ + RATR_MCS12 | RATR_MCS13 | RATR_MCS14 | RATR_MCS15) + +/*------------------------------ Tx Desc definition Macro ------------------------*/ +/* pragma mark -- Tx Desc related definition. -- */ +/* */ +/* */ +/* Rate */ +/* */ +/* CCK Rates, TxHT = 0 */ +#define DESC_RATE1M 0x00 +#define DESC_RATE2M 0x01 +#define DESC_RATE5_5M 0x02 +#define DESC_RATE11M 0x03 + +/* OFDM Rates, TxHT = 0 */ +#define DESC_RATE6M 0x04 +#define DESC_RATE9M 0x05 +#define DESC_RATE12M 0x06 +#define DESC_RATE18M 0x07 +#define DESC_RATE24M 0x08 +#define DESC_RATE36M 0x09 +#define DESC_RATE48M 0x0a +#define DESC_RATE54M 0x0b + +/* MCS Rates, TxHT = 1 */ +#define DESC_RATEMCS0 0x0c +#define DESC_RATEMCS1 0x0d +#define DESC_RATEMCS2 0x0e +#define DESC_RATEMCS3 0x0f +#define DESC_RATEMCS4 0x10 +#define DESC_RATEMCS5 0x11 +#define DESC_RATEMCS6 0x12 +#define DESC_RATEMCS7 0x13 +#define DESC_RATEMCS8 0x14 +#define DESC_RATEMCS9 0x15 +#define DESC_RATEMCS10 0x16 +#define DESC_RATEMCS11 0x17 +#define DESC_RATEMCS12 0x18 +#define DESC_RATEMCS13 0x19 +#define DESC_RATEMCS14 0x1a +#define DESC_RATEMCS15 0x1b +#define DESC_RATEMCS15_SG 0x1c +#define DESC_RATEMCS32 0x20 + +#define REG_P2P_CTWIN 0x0572 /* 1 Byte long (in unit of TU) */ +#define REG_NOA_DESC_SEL 0x05CF +#define REG_NOA_DESC_DURATION 0x05E0 +#define REG_NOA_DESC_INTERVAL 0x05E4 +#define REG_NOA_DESC_START 0x05E8 +#define REG_NOA_DESC_COUNT 0x05EC + +#include "HalVerDef.h" +void dump_chip_info23a(struct hal_version ChipVersion); + + +u8 /* return the final channel plan decision */ +hal_com_get_channel_plan23a( + struct rtw_adapter *padapter, + u8 hw_channel_plan, /* channel plan from HW (efuse/eeprom) */ + u8 sw_channel_plan, /* channel plan from SW (registry/module param) */ + u8 def_channel_plan, /* channel plan used when the former two is invalid */ + bool AutoLoadFail + ); + +u8 MRateToHwRate23a(u8 rate); + +void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS); + +bool +Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe); + +void hal_init_macaddr23a(struct rtw_adapter *adapter); + +void c2h_evt_clear23a(struct rtw_adapter *adapter); +s32 c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf); + +void rtl8723a_set_ampdu_min_space(struct rtw_adapter *padapter, u8 MinSpacingToSet); +void rtl8723a_set_ampdu_factor(struct rtw_adapter *padapter, u8 FactorToSet); +void rtl8723a_set_acm_ctrl(struct rtw_adapter *padapter, u8 ctrl); +void rtl8723a_set_media_status(struct rtw_adapter *padapter, u8 status); +void rtl8723a_set_media_status1(struct rtw_adapter *padapter, u8 status); +void rtl8723a_set_bcn_func(struct rtw_adapter *padapter, u8 val); +void rtl8723a_check_bssid(struct rtw_adapter *padapter, u8 val); +void rtl8723a_mlme_sitesurvey(struct rtw_adapter *padapter, u8 flag); +void rtl8723a_on_rcr_am(struct rtw_adapter *padapter); +void rtl8723a_off_rcr_am(struct rtw_adapter *padapter); +void rtl8723a_set_slot_time(struct rtw_adapter *padapter, u8 slottime); +void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble); +void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec); +void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex); +void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter); +void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2); +void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter); +void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val); +void rtl8723a_bcn_valid(struct rtw_adapter *padapter); +void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause); +void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval); +void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter, + u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2); +void rtl8723a_set_ac_param_vo(struct rtw_adapter *padapter, u32 vo); +void rtl8723a_set_ac_param_vi(struct rtw_adapter *padapter, u32 vi); +void rtl8723a_set_ac_param_be(struct rtw_adapter *padapter, u32 be); +void rtl8723a_set_ac_param_bk(struct rtw_adapter *padapter, u32 bk); +void rtl8723a_set_rxdma_agg_pg_th(struct rtw_adapter *padapter, u8 val); +void rtl8723a_set_nav_upper(struct rtw_adapter *padapter, u32 usNavUpper); +void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain); + +void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val); +void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val); +void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val); +void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val); + +void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val); + +#endif /* __HAL_COMMON_H__ */ diff --git a/drivers/staging/rtl8723au/include/hal_intf.h b/drivers/staging/rtl8723au/include/hal_intf.h new file mode 100644 index 000000000000..d183f4ba1ecb --- /dev/null +++ b/drivers/staging/rtl8723au/include/hal_intf.h @@ -0,0 +1,392 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __HAL_INTF_H__ +#define __HAL_INTF_H__ + +#include +#include + +enum RTL871X_HCI_TYPE { + RTW_PCIE = BIT0, + RTW_USB = BIT1, + RTW_SDIO = BIT2, + RTW_GSPI = BIT3, +}; + +enum _CHIP_TYPE { + NULL_CHIP_TYPE, + RTL8712_8188S_8191S_8192S, + RTL8188C_8192C, + RTL8192D, + RTL8723A, + RTL8188E, + MAX_CHIP_TYPE +}; + +enum HW_VARIABLES { + HW_VAR_MEDIA_STATUS, + HW_VAR_MEDIA_STATUS1, + HW_VAR_SET_OPMODE, + HW_VAR_MAC_ADDR, + HW_VAR_BSSID, + HW_VAR_INIT_RTS_RATE, + HW_VAR_BASIC_RATE, + HW_VAR_TXPAUSE, + HW_VAR_BCN_FUNC, + HW_VAR_CORRECT_TSF, + HW_VAR_CHECK_BSSID, + HW_VAR_MLME_DISCONNECT, + HW_VAR_MLME_SITESURVEY, + HW_VAR_MLME_JOIN, + HW_VAR_ON_RCR_AM, + HW_VAR_OFF_RCR_AM, + HW_VAR_BEACON_INTERVAL, + HW_VAR_SLOT_TIME, + HW_VAR_RESP_SIFS, + HW_VAR_ACK_PREAMBLE, + HW_VAR_SEC_CFG, + HW_VAR_BCN_VALID, + HW_VAR_RF_TYPE, + HW_VAR_DM_FLAG, + HW_VAR_DM_FUNC_OP, + HW_VAR_DM_FUNC_SET, + HW_VAR_DM_FUNC_CLR, + HW_VAR_CAM_EMPTY_ENTRY, + HW_VAR_CAM_INVALID_ALL, + HW_VAR_CAM_WRITE, + HW_VAR_CAM_READ, + HW_VAR_AC_PARAM_VO, + HW_VAR_AC_PARAM_VI, + HW_VAR_AC_PARAM_BE, + HW_VAR_AC_PARAM_BK, + HW_VAR_ACM_CTRL, + HW_VAR_AMPDU_MIN_SPACE, + HW_VAR_AMPDU_FACTOR, + HW_VAR_RXDMA_AGG_PG_TH, + HW_VAR_SET_RPWM, + HW_VAR_H2C_FW_PWRMODE, + HW_VAR_H2C_FW_JOINBSSRPT, + HW_VAR_FWLPS_RF_ON, + HW_VAR_H2C_FW_P2P_PS_OFFLOAD, + HW_VAR_TDLS_WRCR, + HW_VAR_TDLS_INIT_CH_SEN, + HW_VAR_TDLS_RS_RCR, + HW_VAR_TDLS_DONE_CH_SEN, + HW_VAR_INITIAL_GAIN, + HW_VAR_TRIGGER_GPIO_0, + HW_VAR_BT_SET_COEXIST, + HW_VAR_BT_ISSUE_DELBA, + HW_VAR_CURRENT_ANTENNA, + HW_VAR_ANTENNA_DIVERSITY_LINK, + HW_VAR_ANTENNA_DIVERSITY_SELECT, + HW_VAR_SWITCH_EPHY_WoWLAN, + HW_VAR_EFUSE_BYTES, + HW_VAR_EFUSE_BT_BYTES, + HW_VAR_FIFO_CLEARN_UP, + HW_VAR_CHECK_TXBUF, + HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ + /* The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. */ + /* Unit in microsecond. 0 means disable this function. */ + HW_VAR_NAV_UPPER, + HW_VAR_RPT_TIMER_SETTING, + HW_VAR_TX_RPT_MAX_MACID, + HW_VAR_H2C_MEDIA_STATUS_RPT, + HW_VAR_CHK_HI_QUEUE_EMPTY, + HW_VAR_READ_LLT_TAB, +}; + +enum hal_def_variable { + HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, + HAL_DEF_IS_SUPPORT_ANT_DIV, + HAL_DEF_CURRENT_ANTENNA, + HAL_DEF_DRVINFO_SZ, + HAL_DEF_MAX_RECVBUF_SZ, + HAL_DEF_RX_PACKET_OFFSET, + HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */ + HAL_DEF_DBG_DM_FUNC,/* for dbg */ + HAL_DEF_RA_DECISION_RATE, + HAL_DEF_RA_SGI, + HAL_DEF_PT_PWR_STATUS, + HW_VAR_MAX_RX_AMPDU_FACTOR, + HW_DEF_RA_INFO_DUMP, + HAL_DEF_DBG_DUMP_TXPKT, + HW_DEF_FA_CNT_DUMP, + HW_DEF_ODM_DBG_FLAG, +}; + +enum hal_odm_variable { + HAL_ODM_STA_INFO, + HAL_ODM_P2P_STATE, + HAL_ODM_WIFI_DISPLAY_STATE, +}; + +enum hal_intf_ps_func { + HAL_USB_SELECT_SUSPEND, + HAL_MAX_ID, +}; + +struct hal_ops { + u32 (*hal_power_on)(struct rtw_adapter *padapter); + u32 (*hal_init)(struct rtw_adapter *padapter); + u32 (*hal_deinit)(struct rtw_adapter *padapter); + + void (*free_hal_data)(struct rtw_adapter *padapter); + + u32 (*inirp_init)(struct rtw_adapter *padapter); + u32 (*inirp_deinit)(struct rtw_adapter *padapter); + + s32 (*init_xmit_priv)(struct rtw_adapter *padapter); + void (*free_xmit_priv)(struct rtw_adapter *padapter); + + s32 (*init_recv_priv)(struct rtw_adapter *padapter); + void (*free_recv_priv)(struct rtw_adapter *padapter); + + void (*InitSwLeds)(struct rtw_adapter *padapter); + void (*DeInitSwLeds)(struct rtw_adapter *padapter); + + void (*dm_init)(struct rtw_adapter *padapter); + void (*dm_deinit)(struct rtw_adapter *padapter); + void (*read_chip_version)(struct rtw_adapter *padapter); + + void (*init_default_value)(struct rtw_adapter *padapter); + + void (*intf_chip_configure)(struct rtw_adapter *padapter); + + void (*read_adapter_info)(struct rtw_adapter *padapter); + + void (*enable_interrupt)(struct rtw_adapter *padapter); + void (*disable_interrupt)(struct rtw_adapter *padapter); + s32 (*interrupt_handler)(struct rtw_adapter *padapter); + void (*set_bwmode_handler)(struct rtw_adapter *padapter, + enum ht_channel_width Bandwidth, u8 Offset); + void (*set_channel_handler)(struct rtw_adapter *padapter, u8 channel); + + void (*hal_dm_watchdog)(struct rtw_adapter *padapter); + + void (*SetHwRegHandler)(struct rtw_adapter *padapter, + u8 variable, u8 *val); + void (*GetHwRegHandler)(struct rtw_adapter *padapter, + u8 variable, u8 *val); + + u8 (*GetHalDefVarHandler)(struct rtw_adapter *padapter, + enum hal_def_variable eVariable, + void *pValue); + u8 (*SetHalDefVarHandler)(struct rtw_adapter *padapter, + enum hal_def_variable eVariable, + void *pValue); + + void (*GetHalODMVarHandler)(struct rtw_adapter *padapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet); + void (*SetHalODMVarHandler)(struct rtw_adapter *padapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet); + + void (*UpdateRAMaskHandler)(struct rtw_adapter *padapter, + u32 mac_id, u8 rssi_level); + void (*SetBeaconRelatedRegistersHandler)(struct rtw_adapter *padapter); + + void (*Add_RateATid)(struct rtw_adapter *padapter, u32 bitmap, + u8 arg, u8 rssi_level); + void (*run_thread)(struct rtw_adapter *padapter); + void (*cancel_thread)(struct rtw_adapter *padapter); + + u8 (*interface_ps_func)(struct rtw_adapter *padapter, + enum hal_intf_ps_func efunc_id, u8 *val); + + s32 (*hal_xmit)(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); + s32 (*mgnt_xmit)(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe); + s32 (*hal_xmitframe_enqueue)(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); + + u32 (*read_bbreg)(struct rtw_adapter *padapter, u32 RegAddr, + u32 BitMask); + void (*write_bbreg)(struct rtw_adapter *padapter, u32 RegAddr, + u32 BitMask, u32 Data); + u32 (*read_rfreg)(struct rtw_adapter *padapter, u32 eRFPath, + u32 RegAddr, u32 BitMask); + void (*write_rfreg)(struct rtw_adapter *padapter, u32 eRFPath, + u32 RegAddr, u32 BitMask, u32 Data); + + void (*EfusePowerSwitch)(struct rtw_adapter *padapter, u8 bWrite, + u8 PwrState); + void (*ReadEFuse)(struct rtw_adapter *padapter, u8 efuseType, + u16 _offset, u16 _size_byte, u8 *pbuf); + void (*EFUSEGetEfuseDefinition)(struct rtw_adapter *padapter, + u8 efuseType, u8 type, void *pOut); + u16 (*EfuseGetCurrentSize)(struct rtw_adapter *padapter, u8 efuseType); + int (*Efuse_PgPacketRead23a)(struct rtw_adapter *padapter, + u8 offset, u8 *data); + int (*Efuse_PgPacketWrite23a)(struct rtw_adapter *padapter, + u8 offset, u8 word_en, u8 *data); + u8 (*Efuse_WordEnableDataWrite23a)(struct rtw_adapter *padapter, + u16 efuse_addr, u8 word_en, + u8 *data); + bool (*Efuse_PgPacketWrite23a_BT)(struct rtw_adapter *padapter, + u8 offset, u8 word_en, u8 *data); + + void (*sreset_init_value23a)(struct rtw_adapter *padapter); + void (*sreset_reset_value23a)(struct rtw_adapter *padapter); + void (*silentreset)(struct rtw_adapter *padapter); + void (*sreset_xmit_status_check)(struct rtw_adapter *padapter); + void (*sreset_linked_status_check) (struct rtw_adapter *padapter); + u8 (*sreset_get_wifi_status23a)(struct rtw_adapter *padapter); + bool (*sreset_inprogress)(struct rtw_adapter *padapter); + + void (*hal_notch_filter)(struct rtw_adapter *adapter, bool enable); + void (*hal_reset_security_engine)(struct rtw_adapter *adapter); + s32 (*c2h_handler)(struct rtw_adapter *padapter, struct c2h_evt_hdr *c2h_evt); + c2h_id_filter c2h_id_filter_ccx; +}; + +enum rt_eeprom_type { + EEPROM_93C46, + EEPROM_93C56, + EEPROM_BOOT_EFUSE, +}; + + + +#define RF_CHANGE_BY_INIT 0 +#define RF_CHANGE_BY_IPS BIT28 +#define RF_CHANGE_BY_PS BIT29 +#define RF_CHANGE_BY_HW BIT30 +#define RF_CHANGE_BY_SW BIT31 + +enum hardware_type { + HARDWARE_TYPE_RTL8180, + HARDWARE_TYPE_RTL8185, + HARDWARE_TYPE_RTL8187, + HARDWARE_TYPE_RTL8188, + HARDWARE_TYPE_RTL8190P, + HARDWARE_TYPE_RTL8192E, + HARDWARE_TYPE_RTL819xU, + HARDWARE_TYPE_RTL8192SE, + HARDWARE_TYPE_RTL8192SU, + HARDWARE_TYPE_RTL8192CE, + HARDWARE_TYPE_RTL8192CU, + HARDWARE_TYPE_RTL8192DE, + HARDWARE_TYPE_RTL8192DU, + HARDWARE_TYPE_RTL8723AE, + HARDWARE_TYPE_RTL8723AU, + HARDWARE_TYPE_RTL8723AS, + HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8188EU, + HARDWARE_TYPE_RTL8188ES, + HARDWARE_TYPE_MAX, +}; + +#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) +#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) + +extern int rtw_ht_enable23A; +extern int rtw_cbw40_enable23A; +extern int rtw_ampdu_enable23A;/* for enable tx_ampdu */ + +void rtw_hal_def_value_init23a(struct rtw_adapter *padapter); +int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal); +int rtw_resume_process23a(struct rtw_adapter *padapter); + +void rtw_hal_free_data23a(struct rtw_adapter *padapter); + +void rtw_hal_dm_init23a(struct rtw_adapter *padapter); +void rtw_hal_dm_deinit23a(struct rtw_adapter *padapter); +void rtw_hal_sw_led_init23a(struct rtw_adapter *padapter); +void rtw_hal_sw_led_deinit23a(struct rtw_adapter *padapter); + +u32 rtw_hal_power_on23a(struct rtw_adapter *padapter); +uint rtw_hal_init23a(struct rtw_adapter *padapter); +uint rtw_hal_deinit23a(struct rtw_adapter *padapter); +void rtw_hal_stop(struct rtw_adapter *padapter); +void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val); +void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val); + +void rtw_hal_chip_configure23a(struct rtw_adapter *padapter); +void rtw_hal_read_chip_info23a(struct rtw_adapter *padapter); +void rtw_hal_read_chip_version23a(struct rtw_adapter *padapter); + +u8 rtw_hal_set_def_var23a(struct rtw_adapter *padapter, + enum hal_def_variable eVariable, + void *pValue); +u8 rtw_hal_get_def_var23a(struct rtw_adapter *padapter, + enum hal_def_variable eVariable, + void *pValue); + +void rtw_hal_set_odm_var23a(struct rtw_adapter *padapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet); +void rtw_hal_get_odm_var23a(struct rtw_adapter *padapter, + enum hal_odm_variable eVariable, + void *pValue1, bool bSet); + +void rtw_hal_enable_interrupt23a(struct rtw_adapter *padapter); +void rtw_hal_disable_interrupt23a(struct rtw_adapter *padapter); + +u32 rtw_hal_inirp_init23a(struct rtw_adapter *padapter); +u32 rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter); + +u8 rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter, + enum hal_intf_ps_func efunc_id, u8 *val); + +s32 rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +s32 rtw_hal_xmit23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +s32 rtw_hal_mgnt_xmit23a(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe); + +s32 rtw_hal_init23a_xmit_priv(struct rtw_adapter *padapter); +void rtw_hal_free_xmit_priv23a(struct rtw_adapter *padapter); + +s32 rtw_hal_init23a_recv_priv(struct rtw_adapter *padapter); +void rtw_hal_free_recv_priv23a(struct rtw_adapter *padapter); + +void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level); +void rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); +void rtw_hal_clone_data(struct rtw_adapter *dst_padapter, struct rtw_adapter *src_padapter); +void rtw_hal_start_thread23a(struct rtw_adapter *padapter); +void rtw_hal_stop_thread23a(struct rtw_adapter *padapter); + +void rtw_hal_bcn_related_reg_setting23a(struct rtw_adapter *padapter); + +u32 rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask); +void rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); +u32 rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask); +void rtw_hal_write_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); + +s32 rtw_hal_interrupt_handler23a(struct rtw_adapter *padapter); + +void rtw_hal_set_bwmode23a(struct rtw_adapter *padapter, + enum ht_channel_width Bandwidth, u8 Offset); +void rtw_hal_set_chan23a(struct rtw_adapter *padapter, u8 channel); +void rtw_hal_dm_watchdog23a(struct rtw_adapter *padapter); + +void rtw_hal_sreset_init23a(struct rtw_adapter *padapter); +void rtw_hal_sreset_reset23a(struct rtw_adapter *padapter); +void rtw_hal_sreset_reset23a_value23a(struct rtw_adapter *padapter); +void rtw_hal_sreset_xmit_status_check23a(struct rtw_adapter *padapter); +void rtw_hal_sreset_linked_status_check23a (struct rtw_adapter *padapter); +u8 rtw_hal_sreset_get_wifi_status23a(struct rtw_adapter *padapter); +bool rtw_hal_sreset_inprogress(struct rtw_adapter *padapter); + +void rtw_hal_notch_filter23a(struct rtw_adapter *adapter, bool enable); +void rtw_hal_reset_security_engine23a(struct rtw_adapter *adapter); + +s32 rtw_hal_c2h_handler23a(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt); +c2h_id_filter rtw_hal_c2h_id_filter_ccx23a(struct rtw_adapter *adapter); + +#endif /* __HAL_INTF_H__ */ diff --git a/drivers/staging/rtl8723au/include/ieee80211.h b/drivers/staging/rtl8723au/include/ieee80211.h new file mode 100644 index 000000000000..28e4ab239fb9 --- /dev/null +++ b/drivers/staging/rtl8723au/include/ieee80211.h @@ -0,0 +1,603 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __IEEE80211_H +#define __IEEE80211_H + +#include +#include +#include "linux/ieee80211.h" +#include "wifi.h" + +#include + +#if (WIRELESS_EXT < 22) +#error "Obsolete pre 2007 wireless extensions are not supported" +#endif + + +#define MGMT_QUEUE_NUM 5 + +#ifdef CONFIG_8723AU_AP_MODE + +/* STA flags */ +#define WLAN_STA_AUTH BIT(0) +#define WLAN_STA_ASSOC BIT(1) +#define WLAN_STA_PS BIT(2) +#define WLAN_STA_TIM BIT(3) +#define WLAN_STA_PERM BIT(4) +#define WLAN_STA_AUTHORIZED BIT(5) +#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ +#define WLAN_STA_SHORT_PREAMBLE BIT(7) +#define WLAN_STA_PREAUTH BIT(8) +#define WLAN_STA_WME BIT(9) +#define WLAN_STA_MFP BIT(10) +#define WLAN_STA_HT BIT(11) +#define WLAN_STA_WPS BIT(12) +#define WLAN_STA_MAYBE_WPS BIT(13) +#define WLAN_STA_NONERP BIT(31) + +#endif + +#define IEEE_CMD_SET_WPA_PARAM 1 +#define IEEE_CMD_SET_WPA_IE 2 +#define IEEE_CMD_SET_ENCRYPTION 3 + +#define IEEE_CRYPT_ALG_NAME_LEN 16 + +#define WPA_CIPHER_NONE BIT(0) +#define WPA_CIPHER_WEP40 BIT(1) +#define WPA_CIPHER_WEP104 BIT(2) +#define WPA_CIPHER_TKIP BIT(3) +#define WPA_CIPHER_CCMP BIT(4) + + + +#define WPA_SELECTOR_LEN 4 +extern u8 RTW_WPA_OUI23A_TYPE[] ; +extern u16 RTW_WPA_VERSION23A ; +extern u8 WPA_AUTH_KEY_MGMT_NONE23A[]; +extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X23A[]; +extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[]; +extern u8 WPA_CIPHER_SUITE_NONE23A[]; +extern u8 WPA_CIPHER_SUITE_WEP4023A[]; +extern u8 WPA_CIPHER_SUITE_TKIP23A[]; +extern u8 WPA_CIPHER_SUITE_WRAP23A[]; +extern u8 WPA_CIPHER_SUITE_CCMP23A[]; +extern u8 WPA_CIPHER_SUITE_WEP10423A[]; + + +#define RSN_HEADER_LEN 4 +#define RSN_SELECTOR_LEN 4 + +extern u16 RSN_VERSION_BSD23A; +extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X23A[]; +extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[]; +extern u8 RSN_CIPHER_SUITE_NONE23A[]; +extern u8 RSN_CIPHER_SUITE_WEP4023A[]; +extern u8 RSN_CIPHER_SUITE_TKIP23A[]; +extern u8 RSN_CIPHER_SUITE_WRAP23A[]; +extern u8 RSN_CIPHER_SUITE_CCMP23A[]; +extern u8 RSN_CIPHER_SUITE_WEP10423A[]; + +enum ratr_table_mode { + RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */ + RATR_INX_WIRELESS_NG = 1, /* GN or N */ + RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */ + RATR_INX_WIRELESS_N = 3, + RATR_INX_WIRELESS_GB = 4, + RATR_INX_WIRELESS_G = 5, + RATR_INX_WIRELESS_B = 6, + RATR_INX_WIRELESS_MC = 7, + RATR_INX_WIRELESS_AC_N = 8, +}; + +enum NETWORK_TYPE +{ + WIRELESS_INVALID = 0, + /* Sub-Element */ + WIRELESS_11B = BIT(0), /* tx: cck only , rx: cck only, hw: cck */ + WIRELESS_11G = BIT(1), /* tx: ofdm only, rx: ofdm & cck, hw: cck & ofdm */ + WIRELESS_11A = BIT(2), /* tx: ofdm only, rx: ofdm only, hw: ofdm only */ + WIRELESS_11_24N = BIT(3), /* tx: MCS only, rx: MCS & cck, hw: MCS & cck */ + WIRELESS_11_5N = BIT(4), /* tx: MCS only, rx: MCS & ofdm, hw: ofdm only */ + /* WIRELESS_AUTO = BIT(5), */ + WIRELESS_AC = BIT(6), + + /* Combination */ + WIRELESS_11BG = (WIRELESS_11B|WIRELESS_11G), /* tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */ + WIRELESS_11G_24N = (WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */ + WIRELESS_11A_5N = (WIRELESS_11A|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */ + WIRELESS_11BG_24N = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */ + WIRELESS_11AGN = (WIRELESS_11A|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */ + WIRELESS_11ABGN = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), +}; + +#define SUPPORTED_24G_NETTYPE_MSK (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N) +#define SUPPORTED_5G_NETTYPE_MSK (WIRELESS_11A | WIRELESS_11_5N) + +#define IsSupported24G(NetType) ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false) +#define IsSupported5G(NetType) ((NetType) & SUPPORTED_5G_NETTYPE_MSK ? true : false) + +#define IsEnableHWCCK(NetType) IsSupported24G(NetType) +#define IsEnableHWOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11_24N|SUPPORTED_5G_NETTYPE_MSK) ? true : false) + +#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType) +#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType) +#define IsSupportedRxMCS(NetType) IsEnableHWOFDM(NetType) + +#define IsSupportedTxCCK(NetType) ((NetType) & (WIRELESS_11B) ? true : false) +#define IsSupportedTxOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11A) ? true : false) +#define IsSupportedTxMCS(NetType) ((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N) ? true : false) + + +struct ieee_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 reserved[32]; + u8 data[0]; + } wpa_ie; + struct{ + int command; + int reason_code; + } mlme; + struct { + u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; +#ifdef CONFIG_8723AU_AP_MODE + struct { + u16 aid; + u16 capability; + int flags; + u8 tx_supp_rates[16]; + struct ieee80211_ht_cap ht_cap; + } add_sta; + struct { + u8 reserved[2];/* for set max_num_sta */ + u8 buf[0]; + } bcn_ie; +#endif + + } u; +}; + + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + +/* QoS,QOS */ +#define NORMAL_ACK 0 +#define NO_ACK 1 +#define NON_EXPLICIT_ACK 2 +#define BLOCK_ACK 3 + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct ieee80211_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ) + + +#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534 +#define WLAN_REASON_EXPIRATION_CHK 65535 + + + +#define IEEE80211_STATMASK_SIGNAL (1<<0) +#define IEEE80211_STATMASK_RSSI (1<<1) +#define IEEE80211_STATMASK_NOISE (1<<2) +#define IEEE80211_STATMASK_RATE (1<<3) +#define IEEE80211_STATMASK_WEMASK 0x7 + + +#define IEEE80211_CCK_MODULATION (1<<0) +#define IEEE80211_OFDM_MODULATION (1<<1) + +#define IEEE80211_24GHZ_BAND (1<<0) +#define IEEE80211_52GHZ_BAND (1<<1) + +#define IEEE80211_CCK_RATE_LEN 4 +#define IEEE80211_NUM_OFDM_RATESLEN 8 + + +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_LEN 8 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + +#define IEEE80211_NUM_OFDM_RATES 8 +#define IEEE80211_NUM_CCK_RATES 4 +#define IEEE80211_OFDM_SHIFT_MASK_A 4 + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 + + + +/* + + 802.11 data frame from AP + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' + +Total: 28-2340 bytes + +*/ + +struct ieee80211_header_data { + u16 frame_ctl; + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + u16 seq_ctrl; +}; + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + + +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_CHANNEL_NUMBER 161 + +#define MAX_WPA_IE_LEN (256) +#define MAX_WPS_IE_LEN (512) +#define MAX_P2P_IE_LEN (256) +#define MAX_WFD_IE_LEN (128) + +#define IW_ESSID_MAX_SIZE 32 + +/* +join_res: +-1: authentication fail +-2: association fail +> 0: TID +*/ + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) + +#define MAXTID 16 + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +/* Baron move to ieee80211.c */ +int ieee80211_is_empty_essid23a(const char *essid, int essid_len); + +enum _PUBLIC_ACTION{ + ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ + ACT_PUBLIC_DSE_ENABLE = 1, + ACT_PUBLIC_DSE_DEENABLE = 2, + ACT_PUBLIC_DSE_REG_LOCATION = 3, + ACT_PUBLIC_EXT_CHL_SWITCH = 4, + ACT_PUBLIC_DSE_MSR_REQ = 5, + ACT_PUBLIC_DSE_MSR_RPRT = 6, + ACT_PUBLIC_MP = 7, /* Measurement Pilot */ + ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8, + ACT_PUBLIC_VENDOR = 9, /* for WIFI_DIRECT */ + ACT_PUBLIC_GAS_INITIAL_REQ = 10, + ACT_PUBLIC_GAS_INITIAL_RSP = 11, + ACT_PUBLIC_GAS_COMEBACK_REQ = 12, + ACT_PUBLIC_GAS_COMEBACK_RSP = 13, + ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14, + ACT_PUBLIC_LOCATION_TRACK = 15, + ACT_PUBLIC_MAX +}; + +#define WME_OUI_TYPE 2 +#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0 +#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1 +#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2 +#define WME_VERSION 1 + + +#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ + +#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ + +/* Represent channel details, subset of ieee80211_channel */ +struct rtw_ieee80211_channel { + /* enum ieee80211_band band; */ + /* u16 center_freq; */ + u16 hw_value; + u32 flags; + /* int max_antenna_gain; */ + /* int max_power; */ + /* int max_reg_power; */ + /* bool beacon_found; */ + /* u32 orig_flags; */ + /* int orig_mag; */ + /* int orig_mpwr; */ +}; + +#define CHAN_FMT \ + /*"band:%d, "*/ \ + /*"center_freq:%u, "*/ \ + "hw_value:%u, " \ + "flags:0x%08x" \ + /*"max_antenna_gain:%d\n"*/ \ + /*"max_power:%d\n"*/ \ + /*"max_reg_power:%d\n"*/ \ + /*"beacon_found:%u\n"*/ \ + /*"orig_flags:0x%08x\n"*/ \ + /*"orig_mag:%d\n"*/ \ + /*"orig_mpwr:%d\n"*/ + +#define CHAN_ARG(channel) \ + /*(channel)->band*/ \ + /*, (channel)->center_freq*/ \ + (channel)->hw_value \ + , (channel)->flags \ + /*, (channel)->max_antenna_gain*/ \ + /*, (channel)->max_power*/ \ + /*, (channel)->max_reg_power*/ \ + /*, (channel)->beacon_found*/ \ + /*, (channel)->orig_flags*/ \ + /*, (channel)->orig_mag*/ \ + /*, (channel)->orig_mpwr*/ \ + +/* Parsed Information Elements */ +struct rtw_ieee802_11_elems { + u8 *ssid; + u8 ssid_len; + u8 *supp_rates; + u8 supp_rates_len; + u8 *fh_params; + u8 fh_params_len; + u8 *ds_params; + u8 ds_params_len; + u8 *cf_params; + u8 cf_params_len; + u8 *tim; + u8 tim_len; + u8 *ibss_params; + u8 ibss_params_len; + u8 *challenge; + u8 challenge_len; + u8 *erp_info; + u8 erp_info_len; + u8 *ext_supp_rates; + u8 ext_supp_rates_len; + u8 *wpa_ie; + u8 wpa_ie_len; + u8 *rsn_ie; + u8 rsn_ie_len; + u8 *wme; + u8 wme_len; + u8 *wme_tspec; + u8 wme_tspec_len; + u8 *wps_ie; + u8 wps_ie_len; + u8 *power_cap; + u8 power_cap_len; + u8 *supp_channels; + u8 supp_channels_len; + u8 *mdie; + u8 mdie_len; + u8 *ftie; + u8 ftie_len; + u8 *timeout_int; + u8 timeout_int_len; + u8 *ht_capabilities; + u8 ht_capabilities_len; + u8 *ht_operation; + u8 ht_operation_len; + u8 *vendor_ht_cap; + u8 vendor_ht_cap_len; +}; + +enum parse_res { + ParseOK = 0, + ParseUnknown = 1, + ParseFailed = -1 +}; + +enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len, + struct rtw_ieee802_11_elems *elems, + int show_errors); + +u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen); +u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen); + +enum secondary_ch_offset { + SCN = 0, /* no secondary channel */ + SCA = 1, /* secondary channel above */ + SCB = 3, /* secondary channel below */ +}; +u8 secondary_ch_offset_to_hal_ch_offset23a(u8 ch_offset); +u8 hal_ch_offset_to_secondary_ch_offset23a(u8 ch_offset); +u8 *rtw_set_ie23a_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, u8 new_ch, u8 ch_switch_cnt); +u8 *rtw_set_ie23a_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset); +u8 *rtw_set_ie23a_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, u8 flags, u16 reason, u16 precedence); + +u8 *rtw_get_ie23a(u8*pbuf, int index, int *len, int limit); +u8 *rtw_get_ie23a_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen); +int rtw_ies_remove_ie23a(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len); + +void rtw_set_supported_rate23a(u8* SupportedRates, uint mode) ; + +unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit); +unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit); +int rtw_get_wpa_cipher_suite23a(u8 *s); +int rtw_get_wpa2_cipher_suite23a(u8 *s); +int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); +int rtw_parse_wpa2_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x); + +int rtw_get_sec_ie23a(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len); + +u8 rtw_is_wps_ie23a(u8 *ie_ptr, uint *wps_ielen); +u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); +u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_attr, u32 *len_attr); +u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_content, uint *len_content); + +/** + * for_each_ie - iterate over continuous IEs + * @ie: + * @buf: + * @buf_len: + */ +#define for_each_ie(ie, buf, buf_len) \ + for (ie = (void*)buf; (((u8*)ie) - ((u8*)buf) + 1) < buf_len; ie = (void*)(((u8*)ie) + *(((u8*)ie)+1) + 2)) + +void dump_ies23a(u8 *buf, u32 buf_len); +void dump_wps_ie23a(u8 *ie, u32 ie_len); + +#ifdef CONFIG_8723AU_P2P +void dump_p2p_ie23a(u8 *ie, u32 ie_len); +u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen); +u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr); +u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content); +u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr); +void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id); +#endif + +#ifdef CONFIG_8723AU_P2P +int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen); +int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id ,u8 *attr_content, uint *attr_contentlen); +#endif /* CONFIG_8723AU_P2P */ + +uint rtw_get_rateset_len23a(u8 *rateset); + +struct registry_priv; +int rtw_generate_ie23a(struct registry_priv *pregistrypriv); + + +int rtw_get_bit_value_from_ieee_value23a(u8 val); + +uint rtw_is_cckrates_included23a(u8 *rate); + +uint rtw_is_cckratesonly_included23a(u8 *rate); + +int rtw_check_network_type23a(unsigned char *rate, int ratelen, int channel); + +void rtw_get_bcn_info23a(struct wlan_network *pnetwork); + +void rtw_macaddr_cfg23a(u8 *mac_addr); + +u16 rtw_mcs_rate23a(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char * MCS_rate); + +int rtw_action_frame_parse23a(const u8 *frame, u32 frame_len, u8* category, u8 *action); +const char *action_public_str23a(u8 action); + +#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8723au/include/ioctl_cfg80211.h b/drivers/staging/rtl8723au/include/ioctl_cfg80211.h new file mode 100644 index 000000000000..0eb9036d7250 --- /dev/null +++ b/drivers/staging/rtl8723au/include/ioctl_cfg80211.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __IOCTL_CFG80211_H__ +#define __IOCTL_CFG80211_H__ + +struct rtw_wdev_invit_info { + u8 token; + u8 flags; + u8 status; + u8 req_op_ch; + u8 rsp_op_ch; +}; + +#define rtw_wdev_invit_info_init(invit_info) \ + do { \ + (invit_info)->token = 0; \ + (invit_info)->flags = 0x00; \ + (invit_info)->status = 0xff; \ + (invit_info)->req_op_ch = 0; \ + (invit_info)->rsp_op_ch = 0; \ + } while (0) + +struct rtw_wdev_priv { + struct wireless_dev *rtw_wdev; + + struct rtw_adapter *padapter; + + struct cfg80211_scan_request *scan_request; + spinlock_t scan_req_lock; + + struct net_device *pmon_ndev;/* for monitor interface */ + char ifname_mon[IFNAMSIZ + 1]; /* name for monitor interface */ + + u8 p2p_enabled; + + u8 provdisc_req_issued; + + struct rtw_wdev_invit_info invit_info; + + bool block; + bool power_mgmt; +}; + +#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w))) + +#define wiphy_to_adapter(x) \ + (struct rtw_adapter *)(((struct rtw_wdev_priv *) \ + wiphy_priv(x))->padapter) + +#define wiphy_to_wdev(x) \ + (struct wireless_dev *)(((struct rtw_wdev_priv *) \ + wiphy_priv(x))->rtw_wdev) + +int rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev); +void rtw_wdev_free(struct wireless_dev *wdev); +void rtw_wdev_unregister(struct wireless_dev *wdev); + +void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter); + +void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter); + +void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter); +void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter); +void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, + bool aborted); + +#ifdef CONFIG_8723AU_AP_MODE +void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter, + u8 *pmgmt_frame, uint frame_len); +void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter, + unsigned char *da, unsigned short reason); +#endif /* CONFIG_8723AU_AP_MODE */ + +void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, + const u8 *buf, size_t len); +void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, + u8 *pmgmt_frame, uint frame_len); +void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, + u8 *pmgmt_frame, uint frame_len); +void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame, + uint frame_len, const char*msg); + +int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, + int type); + +bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter); + +#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp) \ + cfg80211_rx_mgmt((adapter)->rtw_wdev, freq, sig_dbm, buf, len, 0, gfp) + +#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) \ + cfg80211_send_rx_assoc((adapter)->pnetdev, bss, buf, len) + +#define rtw_cfg80211_mgmt_tx_status(adapter, cookie, buf, len, ack, gfp) \ + cfg80211_mgmt_tx_status((adapter)->rtw_wdev, cookie, buf, \ + len, ack, gfp) + +#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan, \ + channel_type, duration, gfp) \ + cfg80211_ready_on_channel((adapter)->rtw_wdev, cookie, chan, \ + duration, gfp) +#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan, \ + chan_type, gfp) \ + cfg80211_remain_on_channel_expired((adapter)->rtw_wdev, \ + cookie, chan, gfp) + +#endif /* __IOCTL_CFG80211_H__ */ diff --git a/drivers/staging/rtl8723au/include/mlme_osdep.h b/drivers/staging/rtl8723au/include/mlme_osdep.h new file mode 100644 index 000000000000..b7132a9a1378 --- /dev/null +++ b/drivers/staging/rtl8723au/include/mlme_osdep.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __MLME_OSDEP_H_ +#define __MLME_OSDEP_H_ + +#include +#include + +void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter); +void rtw_os_indicate_connect23a(struct rtw_adapter *adapter); +void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted); +void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie); + +void rtw_reset_securitypriv23a(struct rtw_adapter *adapter); + +#endif /* _MLME_OSDEP_H_ */ diff --git a/drivers/staging/rtl8723au/include/mp_custom_oid.h b/drivers/staging/rtl8723au/include/mp_custom_oid.h new file mode 100644 index 000000000000..da197cf678a1 --- /dev/null +++ b/drivers/staging/rtl8723au/include/mp_custom_oid.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __CUSTOM_OID_H +#define __CUSTOM_OID_H + +/* 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit */ +/* 0xFF818500 - 0xFF81850F RTL8185 Setup Utility */ +/* 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility */ + +/* For Production Kit with Agilent Equipments */ +/* in order to make our custom oids hopefully somewhat unique */ +/* we will use 0xFF (indicating implementation specific OID) */ +/* 81(first byte of non zero Realtek unique identifier) */ +/* 80 (second byte of non zero Realtek unique identifier) */ +/* XX (the custom OID number - providing 255 possible custom oids) */ + +#define OID_RT_PRO_RESET_DUT 0xFF818000 +#define OID_RT_PRO_SET_DATA_RATE 0xFF818001 +#define OID_RT_PRO_START_TEST 0xFF818002 +#define OID_RT_PRO_STOP_TEST 0xFF818003 +#define OID_RT_PRO_SET_PREAMBLE 0xFF818004 +#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005 +#define OID_RT_PRO_SET_FILTER_BB 0xFF818006 +#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007 +#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008 +#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009 +#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A + +#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D +#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E +#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F +#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010 +#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011 +#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012 +#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013 +#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014 +#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015 +#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016 +#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017 +#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018 +#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019 +#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A +#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B +#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C +#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D +#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E +#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F +#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020 +#define OID_RT_PRO_WRITE_EEPROM 0xFF818021 +#define OID_RT_PRO_READ_EEPROM 0xFF818022 +#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023 +#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024 +#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025 +#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026 +#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027 +#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028 +#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029 +#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A +#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C +/* added by Owen on 04/08/03 for Cameo's request */ +#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D +#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E +#define OID_RT_PRO_SET_MODULATION 0xFF81802F +/* */ + +#define OID_RT_DRIVER_OPTION 0xFF818080 +#define OID_RT_RF_OFF 0xFF818081 +#define OID_RT_AUTH_STATUS 0xFF818082 + +/* */ +#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B +#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C +#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B +#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043 +/* */ + + +/* by Owen for RTL8185 Phy Status Report Utility */ +#define OID_RT_UTILITYfalse_ALARM_COUNTERS 0xFF818580 +#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581 +#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582 +#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583 +#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584 +#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS 0xFF818585 +#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586 + +/* by Owen on 03/09/19-03/09/22 for RTL8185 */ +#define OID_RT_WIRELESS_MODE 0xFF818500 +#define OID_RT_SUPPORTED_RATES 0xFF818501 +#define OID_RT_DESIRED_RATES 0xFF818502 +#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503 +/* */ + +#define OID_RT_GET_CONNECT_STATE 0xFF030001 +#define OID_RT_RESCAN 0xFF030002 +#define OID_RT_SET_KEY_LENGTH 0xFF030003 +#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004 + +#define OID_RT_SET_CHANNEL 0xFF010182 +#define OID_RT_SET_SNIFFER_MODE 0xFF010183 +#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184 +#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185 +#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186 +#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187 +#define OID_RT_GET_TX_RETRY 0xFF010188 +#define OID_RT_GET_RX_RETRY 0xFF010189 +#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A/* S */ +#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B/* S */ + +#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190 +#define OID_RT_GET_TX_BEACON_OK 0xFF010191 +#define OID_RT_GET_TX_BEACON_ERR 0xFF010192 +#define OID_RT_GET_RX_ICV_ERR 0xFF010193 +#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194 +#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195 +#define OID_RT_GET_PREAMBLE_MODE 0xFF010196 +#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197 +#define OID_RT_GET_AP_IP 0xFF010198 +#define OID_RT_GET_CHANNELPLAN 0xFF010199 +#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A +#define OID_RT_SET_BCN_INTVL 0xFF01019B +#define OID_RT_GET_RF_VENDER 0xFF01019C +#define OID_RT_DEDICATE_PROBE 0xFF01019D +#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E + +#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F + +#define OID_RT_GET_CCA_ERR 0xFF0101A0 +#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1 +#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2 + +#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3 +#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4 + +/* by Owen on 03/31/03 for Cameo's request */ +#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5 +/* */ +#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5 +#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6 +#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7 +#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8 +#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9 +#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA +#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB +#define OID_RT_GET_CHANNEL 0xFF0101AC + +#define OID_RT_SET_CHANNELPLAN 0xFF0101AD +#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE +#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF +#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0 +#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1 +#define OID_RT_GET_IS_ROAMING 0xFF0101B2 +#define OID_RT_GET_IS_PRIVACY 0xFF0101B3 +#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4 +#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5 +#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6 +#define OID_RT_RESET_LOG 0xFF0101B7 +#define OID_RT_GET_LOG 0xFF0101B8 +#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9 +#define OID_RT_GET_HEADER_FAIL 0xFF0101BA +#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB +#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC +#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD +#define OID_RT_GET_TX_INFO 0xFF0101BE +#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF +#define OID_RT_RF_READ_WRITE 0xFF0101C0 + +/* For Netgear request. 2005.01.13, by rcnjko. */ +#define OID_RT_FORCED_DATA_RATE 0xFF0101C1 +#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2 +/* For Netgear request. 2005.02.17, by rcnjko. */ +#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3 +/* For AZ project. 2005.06.27, by rcnjko. */ +#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4 + +/* Vincent 8185MP */ +#define OID_RT_PRO_RX_FILTER 0xFF0111C0 + +/* Andy TEST */ +/* define OID_RT_PRO_WRITE_REGISTRY 0xFF0111C1 */ +/* define OID_RT_PRO_READ_REGISTRY 0xFF0111C2 */ +#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1 +#define OID_CE_USB_READ_REGISTRY 0xFF0111C2 + + +#define OID_RT_PRO_SET_INITIAL_GAIN 0xFF0111C3 +#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4 +#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5 +#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6 +#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7 +#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8 +#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9 +#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA + +/* AP OID */ +#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300 +#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301 +#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302 +#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303 +#define OID_RT_AP_SUPPORTED 0xFF010304 /* Determine if driver supports AP mode. 2004.08.27, by rcnjko. */ +#define OID_RT_AP_SET_PASSPHRASE 0xFF010305 /* Set WPA-PSK passphrase into authenticator. 2005.07.08, byrcnjko. */ + +/* 8187MP. 2004.09.06, by rcnjko. */ +#define OID_RT_PRO8187_WI_POLL 0xFF818780 +#define OID_RT_PRO_WRITE_BB_REG 0xFF818781 +#define OID_RT_PRO_READ_BB_REG 0xFF818782 +#define OID_RT_PRO_WRITE_RF_REG 0xFF818783 +#define OID_RT_PRO_READ_RF_REG 0xFF818784 + +/* Meeting House. added by Annie, 2005-07-20. */ +#define OID_RT_MH_VENDER_ID 0xFFEDC100 + +/* 8711 MP OID added 20051230. */ +#define OID_RT_PRO8711_JOIN_BSS 0xFF871100/* S */ + +#define OID_RT_PRO_READ_REGISTER 0xFF871101 /* Q */ +#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 /* S */ + +#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 /* Q */ +#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 /* S */ + +#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 /* S */ + +#define OID_RT_PRO_READ16_EEPROM 0xFF871106 /* Q */ +#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 /* S */ + +#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 /* S */ +#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 /* Q */ + +#define OID_RT_PRO8711_WI_POLL 0xFF87110A /* Q */ +#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B /* Q */ +#define OID_RT_RD_ATTRIB_MEM 0xFF87110C/* Q */ +#define OID_RT_WR_ATTRIB_MEM 0xFF87110D/* S */ + + +/* Method 2 for H2C/C2H */ +#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 /* S */ +#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 /* Q */ +#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 /* S */ +#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 /* Q */ +#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114/* Q */ + +#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 /* Q, S */ + +#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 /* S */ +#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 /* Q,S */ +#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 /* Q */ +#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 /* Q */ + +#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A /* S */ +#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B /* Q */ +#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C /* S */ +#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D /* Q */ +#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E /* S */ +#define OID_RT_POLL_RX_STATUS 0xFF87111F /* Q */ + +#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 /* Q,S */ +#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121/* S */ +#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122/* S */ +#define OID_RT_PRO_READ_TSSI 0xFF871123/* S */ +#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124/* S */ + + +#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 /* Q */ +#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 /* S */ + +/* Method 2 , using workitem */ +#define OID_RT_SET_READ_REG 0xFF871181 /* S */ +#define OID_RT_SET_WRITE_REG 0xFF871182 /* S */ +#define OID_RT_SET_BURST_READ_REG 0xFF871183 /* S */ +#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 /* S */ +#define OID_RT_SET_WRITE_TXCMD 0xFF871185 /* S */ +#define OID_RT_SET_READ16_EEPROM 0xFF871186 /* S */ +#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 /* S */ +#define OID_RT_QRY_POLL_WKITEM 0xFF871188 /* Q */ + +/* For SDIO INTERFACE only */ +#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 /* Q, S */ +#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1 + +/* For USB INTERFACE only */ +#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 /* Q, S */ +#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 /* S */ +#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 /* S */ +#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 /* Q */ +#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 /* Q */ + +#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB /* S */ +#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC /* S */ +#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE + +#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 /* Q, S */ +#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 /* S */ +#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 /* S */ +#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 /* Q */ + +#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 /* Q, S */ + +#define OID_RT_PRO_READ_EFUSE 0xFF871205 /* Q */ +#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 /* S */ +#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 /* Q, S */ +#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 /* Q */ + +#define OID_RT_SET_BANDWIDTH 0xFF871209 /* S */ +#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A /* S */ + +#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B /* S */ + +#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C /* Q */ + +#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D /* S */ + +#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E /* S */ + +#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F /* S */ + +#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 /* Q */ + +#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 /* S */ +#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 /* Q */ +#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 /* Q */ + +#define OID_RT_SET_POWER_DOWN 0xFF871214 /* S */ + +#define OID_RT_GET_POWER_MODE 0xFF871215 /* Q */ + +#define OID_RT_PRO_EFUSE 0xFF871216 /* Q, S */ +#define OID_RT_PRO_EFUSE_MAP 0xFF871217 /* Q, S */ + +#endif /* ifndef __CUSTOM_OID_H */ diff --git a/drivers/staging/rtl8723au/include/odm.h b/drivers/staging/rtl8723au/include/odm.h new file mode 100644 index 000000000000..ac4273288cca --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm.h @@ -0,0 +1,1210 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + + +#ifndef __HALDMOUTSRC_H__ +#define __HALDMOUTSRC_H__ + +/* */ +/* Definition */ +/* */ +/* */ +/* 2011/09/22 MH Define all team supprt ability. */ +/* */ + +/* */ +/* 2011/09/22 MH Define for all teams. Please Define the constan in your precomp header. */ +/* */ +/* define DM_ODM_SUPPORT_AP 0 */ +/* define DM_ODM_SUPPORT_ADSL 0 */ +/* define DM_ODM_SUPPORT_CE 0 */ +/* define DM_ODM_SUPPORT_MP 1 */ + +#define TP_MODE 0 +#define RSSI_MODE 1 +#define TRAFFIC_LOW 0 +#define TRAFFIC_HIGH 1 + + +/* */ +/* 3 Tx Power Tracking */ +/* 3============================================================ */ +#define DPK_DELTA_MAPPING_NUM 13 +#define index_mapping_HP_NUM 15 + + +/* */ +/* 3 PSD Handler */ +/* 3============================================================ */ + +#define AFH_PSD 1 /* 0:normal PSD scan, 1: only do 20 pts PSD */ +#define MODE_40M 0 /* 0:20M, 1:40M */ +#define PSD_TH2 3 +#define PSD_CHMIN 20 /* Minimum channel number for BT AFH */ +#define SIR_STEP_SIZE 3 +#define Smooth_Size_1 5 +#define Smooth_TH_1 3 +#define Smooth_Size_2 10 +#define Smooth_TH_2 4 +#define Smooth_Size_3 20 +#define Smooth_TH_3 4 +#define Smooth_Step_Size 5 +#define Adaptive_SIR 1 +#define PSD_RESCAN 4 +#define PSD_SCAN_INTERVAL 700 /* ms */ + +/* 8723A High Power IGI Setting */ +#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22 +#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28 +#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a + +/* LPS define */ +#define DM_DIG_FA_TH0_LPS 4 /* 4 in lps */ +#define DM_DIG_FA_TH1_LPS 15 /* 15 lps */ +#define DM_DIG_FA_TH2_LPS 30 /* 30 lps */ +#define RSSI_OFFSET_DIG 0x05; + +/* ANT Test */ +#define ANTTESTALL 0x00 /* Ant A or B will be Testing */ +#define ANTTESTA 0x01 /* Ant A will be Testing */ +#define ANTTESTB 0x02 /* Ant B will be testing */ + + +/* */ +/* structure and define */ +/* */ + +/* */ +/* 2011/09/20 MH Add for AP/ADSLpseudo DM structuer requirement. */ +/* We need to remove to other position??? */ +/* */ +struct rtl8723a_priv { + u8 temp; +}; + + +struct dig_t { + u8 Dig_Enable_Flag; + u8 Dig_Ext_Port_Stage; + + int RssiLowThresh; + int RssiHighThresh; + + u32 FALowThresh; + u32 FAHighThresh; + + u8 CurSTAConnectState; + u8 PreSTAConnectState; + u8 CurMultiSTAConnectState; + + u8 PreIGValue; + u8 CurIGValue; + u8 BackupIGValue; + + s8 BackoffVal; + s8 BackoffVal_range_max; + s8 BackoffVal_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 Rssi_val_min; + + u8 PreCCK_CCAThres; + u8 CurCCK_CCAThres; + u8 PreCCKPDState; + u8 CurCCKPDState; + + u8 LargeFAHit; + u8 ForbiddenIGI; + u32 Recover_cnt; + + u8 DIG_Dynamic_MIN_0; + u8 DIG_Dynamic_MIN_1; + bool bMediaConnect_0; + bool bMediaConnect_1; + + u32 AntDiv_RSSI_max; + u32 RSSI_max; +}; + +struct dynamic_pwr_sav { + u8 PreCCAState; + u8 CurCCAState; + + u8 PreRFState; + u8 CurRFState; + + int Rssi_val_min; + + u8 initialize; + u32 Reg874,RegC70,Reg85C,RegA74; +}; + +struct false_alarm_stats { + u32 Cnt_Parity_Fail; + u32 Cnt_Rate_Illegal; + u32 Cnt_Crc8_fail; + u32 Cnt_Mcs_fail; + u32 Cnt_Ofdm_fail; + u32 Cnt_Cck_fail; + u32 Cnt_all; + u32 Cnt_Fast_Fsync; + u32 Cnt_SB_Search_fail; + u32 Cnt_OFDM_CCA; + u32 Cnt_CCK_CCA; + u32 Cnt_CCA_all; + u32 Cnt_BW_USC; /* Gary */ + u32 Cnt_BW_LSC; /* Gary */ +}; + +struct pri_cca { + u8 PriCCA_flag; + u8 intf_flag; + u8 intf_type; + u8 DupRTS_flag; + u8 Monitor_flag; +}; + +struct rx_hp { + u8 RXHP_flag; + u8 PSD_func_trigger; + u8 PSD_bitmap_RXHP[80]; + u8 Pre_IGI; + u8 Cur_IGI; + u8 Pre_pw_th; + u8 Cur_pw_th; + bool First_time_enter; + bool RXHP_enable; + u8 TP_Mode; + struct timer_list PSDTimer; +}; + +#define ASSOCIATE_ENTRY_NUM 32 /* Max size of AsocEntry[]. */ +#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM + +/* This indicates two different the steps. */ +/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */ +/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */ +/* with original RSSI to determine if it is necessary to switch antenna. */ +#define SWAW_STEP_PEAK 0 +#define SWAW_STEP_DETERMINE 1 + +#define TP_MODE 0 +#define RSSI_MODE 1 +#define TRAFFIC_LOW 0 +#define TRAFFIC_HIGH 1 + +struct sw_ant_sw { + u8 try_flag; + s32 PreRSSI; + u8 CurAntenna; + u8 PreAntenna; + u8 RSSI_Trying; + u8 TestMode; + u8 bTriggerAntennaSwitch; + u8 SelectAntennaMap; + u8 RSSI_target; + + /* Before link Antenna Switch check */ + u8 SWAS_NoLink_State; + u32 SWAS_NoLink_BK_Reg860; + bool ANTA_ON; /* To indicate Ant A is or not */ + bool ANTB_ON; /* To indicate Ant B is on or not */ + + s32 RSSI_sum_A; + s32 RSSI_sum_B; + s32 RSSI_cnt_A; + s32 RSSI_cnt_B; + + u64 lastTxOkCnt; + u64 lastRxOkCnt; + u64 TXByteCnt_A; + u64 TXByteCnt_B; + u64 RXByteCnt_A; + u64 RXByteCnt_B; + u8 TrafficLoad; + struct timer_list SwAntennaSwitchTimer; +}; + +struct edca_turbo { + bool bCurrentTurboEDCA; + bool bIsCurRDLState; + u32 prv_traffic_idx; /* edca turbo */ + +}; + +struct odm_rate_adapt { + u8 Type; /* DM_Type_ByFW/DM_Type_ByDriver */ + u8 HighRSSIThresh; /* if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH */ + u8 LowRSSIThresh; /* if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW */ + u8 RATRState; /* Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */ + u32 LastRATR; /* RATR Register Content */ +}; + +#define IQK_MAC_REG_NUM 4 +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM_MAX 10 +#define IQK_BB_REG_NUM 9 +#define HP_THERMAL_NUM 8 + +#define AVG_THERMAL_NUM 8 +#define IQK_Matrix_REG_NUM 8 +#define IQK_Matrix_Settings_NUM 1+24+21 + +#define DM_Type_ByFW 0 +#define DM_Type_ByDriver 1 + +/* */ +/* Declare for common info */ +/* */ +/* Declare for common info */ +/* */ +#define MAX_PATH_NUM_92CS 2 + +struct odm_phy_info { + u8 RxPWDBAll; + u8 SignalQuality; /* in 0-100 index. */ + u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */ + u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* in 0~100 index */ + s8 RxPower; /* in dBm Translate from PWdB */ + s8 RecvSignalPower;/* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */ + u8 BTRxRSSIPercentage; + u8 SignalStrength; /* in 0-100 index. */ + u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */ + u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */ +}; + + +struct odm_phy_dbg_info { + /* ODM Write,debug info */ + s8 RxSNRdB[MAX_PATH_NUM_92CS]; + u64 NumQryPhyStatus; + u64 NumQryPhyStatusCCK; + u64 NumQryPhyStatusOFDM; + /* Others */ + s32 RxEVM[MAX_PATH_NUM_92CS]; + +}; + +struct odm_packet_info { + u8 Rate; + u8 StationID; + bool bPacketMatchBSSID; + bool bPacketToSelf; + bool bPacketBeacon; +}; + +struct odm_mac_info { + u8 test; + +}; + + +enum { + /* BB Team */ + ODM_DIG = 0x00000001, + ODM_HIGH_POWER = 0x00000002, + ODM_CCK_CCA_TH = 0x00000004, + ODM_FA_STATISTICS = 0x00000008, + ODM_RAMASK = 0x00000010, + ODM_RSSI_MONITOR = 0x00000020, + ODM_SW_ANTDIV = 0x00000040, + ODM_HW_ANTDIV = 0x00000080, + ODM_BB_PWRSV = 0x00000100, + ODM_2TPATHDIV = 0x00000200, + ODM_1TPATHDIV = 0x00000400, + ODM_PSD2AFH = 0x00000800 +}; + +/* */ +/* 2011/20/20 MH For MP driver RT_WLAN_STA = struct sta_info */ +/* Please declare below ODM relative info in your STA info structure. */ +/* */ +struct odm_sta_info { + /* Driver Write */ + bool bUsed; /* record the sta status link or not? */ + u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ + + /* ODM Write */ + /* 1 PHY_STATUS_INFO */ + u8 RSSI_Path[4]; /* */ + u8 RSSI_Ave; + u8 RXEVM[4]; + u8 RXSNR[4]; + + /* ODM Write */ + /* 1 TX_INFO (may changed by IC) */ + + /* */ + /* Please use compile flag to disable the structure for other IC except 88E. */ + /* Move To lower layer. */ + /* */ + /* ODM Write Wilson will handle this part(said by Luke.Lee) */ +}; + +/* */ +/* 2011/10/20 MH Define Common info enum for all team. */ +/* */ + +enum odm_cmninfo { + /* Fixed value: */ + /* */ + + ODM_CMNINFO_PLATFORM = 0, + ODM_CMNINFO_ABILITY, /* enum odm_ability */ + ODM_CMNINFO_INTERFACE, /* enum odm_interface_def */ + ODM_CMNINFO_MP_TEST_CHIP, + ODM_CMNINFO_IC_TYPE, /* enum odm_ic_type_def */ + ODM_CMNINFO_CUT_VER, /* enum odm_cut_version */ + ODM_CMNINFO_FAB_VER, /* enum odm_fab_version */ + ODM_CMNINFO_RF_TYPE, /* enum rf_path_def or enum odm_rf_type? */ + ODM_CMNINFO_BOARD_TYPE, /* enum odm_board_type */ + ODM_CMNINFO_EXT_LNA, /* true */ + ODM_CMNINFO_EXT_PA, + ODM_CMNINFO_EXT_TRSW, + ODM_CMNINFO_PATCH_ID, /* CUSTOMER ID */ + ODM_CMNINFO_BINHCT_TEST, + ODM_CMNINFO_BWIFI_TEST, + ODM_CMNINFO_SMART_CONCURRENT, + + + /* */ + /* Dynamic value: */ + /* */ + ODM_CMNINFO_MAC_PHY_MODE, /* enum odm_mac_phy_mode */ + ODM_CMNINFO_TX_UNI, + ODM_CMNINFO_RX_UNI, + ODM_CMNINFO_WM_MODE, /* enum odm_wireless_mode */ + ODM_CMNINFO_BAND, /* enum odm_band_type */ + ODM_CMNINFO_SEC_CHNL_OFFSET, /* enum odm_sec_chnl_offset */ + ODM_CMNINFO_SEC_MODE, /* enum odm_security */ + ODM_CMNINFO_BW, /* enum odm_band_width */ + ODM_CMNINFO_CHNL, + + ODM_CMNINFO_DMSP_GET_VALUE, + ODM_CMNINFO_BUDDY_ADAPTOR, + ODM_CMNINFO_DMSP_IS_MASTER, + ODM_CMNINFO_SCAN, + ODM_CMNINFO_POWER_SAVING, + ODM_CMNINFO_ONE_PATH_CCA, /* enum odm_cca_path */ + ODM_CMNINFO_DRV_STOP, + ODM_CMNINFO_PNP_IN, + ODM_CMNINFO_INIT_ON, + ODM_CMNINFO_ANT_TEST, + ODM_CMNINFO_NET_CLOSED, + ODM_CMNINFO_MP_MODE, + + ODM_CMNINFO_WIFI_DIRECT, + ODM_CMNINFO_WIFI_DISPLAY, + ODM_CMNINFO_LINK, + ODM_CMNINFO_RSSI_MIN, + ODM_CMNINFO_DBG_COMP, /* u64 */ + ODM_CMNINFO_DBG_LEVEL, /* u32 */ + ODM_CMNINFO_RA_THRESHOLD_HIGH, /* u8 */ + ODM_CMNINFO_RA_THRESHOLD_LOW, /* u8 */ + ODM_CMNINFO_RF_ANTENNA_TYPE, /* u8 */ + ODM_CMNINFO_BT_DISABLED, + ODM_CMNINFO_BT_OPERATION, + ODM_CMNINFO_BT_DIG, + ODM_CMNINFO_BT_BUSY, /* Check Bt is using or not */ + ODM_CMNINFO_BT_DISABLE_EDCA, + + /* */ + /* Dynamic ptr array hook itms. */ + /* */ + ODM_CMNINFO_STA_STATUS, + ODM_CMNINFO_PHY_STATUS, + ODM_CMNINFO_MAC_STATUS, + + ODM_CMNINFO_MAX, +}; + +/* Define ODM support ability. ODM_CMNINFO_ABILITY */ +enum { + /* BB ODM section BIT 0-15 */ + ODM_BB_DIG = BIT0, + ODM_BB_RA_MASK = BIT1, + ODM_BB_DYNAMIC_TXPWR = BIT2, + ODM_BB_FA_CNT = BIT3, + ODM_BB_RSSI_MONITOR = BIT4, + ODM_BB_CCK_PD = BIT5, + ODM_BB_ANT_DIV = BIT6, + ODM_BB_PWR_SAVE = BIT7, + ODM_BB_PWR_TRAIN = BIT8, + ODM_BB_RATE_ADAPTIVE = BIT9, + ODM_BB_PATH_DIV = BIT10, + ODM_BB_PSD = BIT11, + ODM_BB_RXHP = BIT12, + + /* MAC DM section BIT 16-23 */ + ODM_MAC_EDCA_TURBO = BIT16, + ODM_MAC_EARLY_MODE = BIT17, + + /* RF ODM section BIT 24-31 */ + ODM_RF_TX_PWR_TRACK = BIT24, + ODM_RF_RX_GAIN_TRACK = BIT25, + ODM_RF_CALIBRATION = BIT26, + +}; + +/* ODM_CMNINFO_INTERFACE */ +enum odm_interface_def { + ODM_ITRF_PCIE = 0x1, + ODM_ITRF_USB = 0x2, + ODM_ITRF_SDIO = 0x4, + ODM_ITRF_ALL = 0x7, +}; + +/* ODM_CMNINFO_IC_TYPE */ +enum odm_ic_type_def { + ODM_RTL8192S = BIT0, + ODM_RTL8192C = BIT1, + ODM_RTL8192D = BIT2, + ODM_RTL8723A = BIT3, + ODM_RTL8188E = BIT4, + ODM_RTL8812 = BIT5, + ODM_RTL8821 = BIT6, +}; + +#define ODM_IC_11N_SERIES \ + (ODM_RTL8192S|ODM_RTL8192C|ODM_RTL8192D|ODM_RTL8723A|ODM_RTL8188E) +#define ODM_IC_11AC_SERIES (ODM_RTL8812) + +/* ODM_CMNINFO_CUT_VER */ +enum odm_cut_version { + ODM_CUT_A = 1, + ODM_CUT_B = 2, + ODM_CUT_C = 3, + ODM_CUT_D = 4, + ODM_CUT_E = 5, + ODM_CUT_F = 6, + ODM_CUT_TEST = 7, +}; + +/* ODM_CMNINFO_FAB_VER */ +enum odm_fab_version { + ODM_TSMC = 0, + ODM_UMC = 1, +}; + +/* ODM_CMNINFO_RF_TYPE */ +/* For example 1T2R (A+AB = BIT0|BIT4|BIT5) */ +enum rf_path_def { + ODM_RF_TX_A = BIT0, + ODM_RF_TX_B = BIT1, + ODM_RF_TX_C = BIT2, + ODM_RF_TX_D = BIT3, + ODM_RF_RX_A = BIT4, + ODM_RF_RX_B = BIT5, + ODM_RF_RX_C = BIT6, + ODM_RF_RX_D = BIT7, +}; + + +enum odm_rf_type { + ODM_1T1R = 0, + ODM_1T2R = 1, + ODM_2T2R = 2, + ODM_2T3R = 3, + ODM_2T4R = 4, + ODM_3T3R = 5, + ODM_3T4R = 6, + ODM_4T4R = 7, +}; + +/* ODM Dynamic common info value definition */ + +enum odm_mac_phy_mode { + ODM_SMSP = 0, + ODM_DMSP = 1, + ODM_DMDP = 2, +}; + + +enum odm_bt_coexist { + ODM_BT_BUSY = 1, + ODM_BT_ON = 2, + ODM_BT_OFF = 3, + ODM_BT_NONE = 4, +}; + +/* ODM_CMNINFO_OP_MODE */ +enum odm_operation_mode { + ODM_NO_LINK = BIT0, + ODM_LINK = BIT1, + ODM_SCAN = BIT2, + ODM_POWERSAVE = BIT3, + ODM_AP_MODE = BIT4, + ODM_CLIENT_MODE = BIT5, + ODM_AD_HOC = BIT6, + ODM_WIFI_DIRECT = BIT7, + ODM_WIFI_DISPLAY = BIT8, +}; + +/* ODM_CMNINFO_WM_MODE */ +enum odm_wireless_mode { + ODM_WM_UNKNOW = 0x0, + ODM_WM_B = BIT0, + ODM_WM_G = BIT1, + ODM_WM_A = BIT2, + ODM_WM_N24G = BIT3, + ODM_WM_N5G = BIT4, + ODM_WM_AUTO = BIT5, + ODM_WM_AC = BIT6, +}; + +/* ODM_CMNINFO_BAND */ +enum odm_band_type { + ODM_BAND_2_4G = BIT0, + ODM_BAND_5G = BIT1, + +}; + +/* ODM_CMNINFO_SEC_CHNL_OFFSET */ +enum odm_sec_chnl_offset { + ODM_DONT_CARE = 0, + ODM_BELOW = 1, + ODM_ABOVE = 2 +}; + +/* ODM_CMNINFO_SEC_MODE */ +enum odm_security { + ODM_SEC_OPEN = 0, + ODM_SEC_WEP40 = 1, + ODM_SEC_TKIP = 2, + ODM_SEC_RESERVE = 3, + ODM_SEC_AESCCMP = 4, + ODM_SEC_WEP104 = 5, + ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */ + ODM_SEC_SMS4 = 7, +}; + +/* ODM_CMNINFO_BW */ +enum odm_band_width { + ODM_BW20M = 0, + ODM_BW40M = 1, + ODM_BW80M = 2, + ODM_BW160M = 3, + ODM_BW10M = 4, +}; + +/* ODM_CMNINFO_CHNL */ + +/* ODM_CMNINFO_BOARD_TYPE */ +enum odm_board_type { + ODM_BOARD_NORMAL = 0, + ODM_BOARD_HIGHPWR = 1, + ODM_BOARD_MINICARD = 2, + ODM_BOARD_SLIM = 3, + ODM_BOARD_COMBO = 4, + +}; + +/* ODM_CMNINFO_ONE_PATH_CCA */ +enum odm_cca_path { + ODM_CCA_2R = 0, + ODM_CCA_1R_A = 1, + ODM_CCA_1R_B = 2, +}; + +struct odm_ra_info { + u8 RateID; + u32 RateMask; + u32 RAUseRate; + u8 RateSGI; + u8 RssiStaRA; + u8 PreRssiStaRA; + u8 SGIEnable; + u8 DecisionRate; + u8 PreRate; + u8 HighestRate; + u8 LowestRate; + u32 NscUp; + u32 NscDown; + u16 RTY[5]; + u32 TOTAL; + u16 DROP; + u8 Active; + u16 RptTime; + u8 RAWaitingCounter; + u8 RAPendingCounter; + u8 PTActive; /* on or off */ + u8 PTTryState; /* 0 trying state, 1 for decision state */ + u8 PTStage; /* 0~6 */ + u8 PTStopCount; /* Stop PT counter */ + u8 PTPreRate; /* if rate change do PT */ + u8 PTPreRssi; /* if RSSI change 5% do PT */ + u8 PTModeSS; /* decide whitch rate should do PT */ + u8 RAstage; /* StageRA, decide how many times RA will be done between PT */ + u8 PTSmoothFactor; +}; + +struct iqk_matrix_regs_set { + bool bIQKDone; + s32 Value[1][IQK_Matrix_REG_NUM]; +}; + +struct odm_rf_cal_t { + /* for tx power tracking */ + + u32 RegA24; /* for TempCCK */ + s32 RegE94; + s32 RegE9C; + s32 RegEB4; + s32 RegEBC; + + /* u8 bTXPowerTracking; */ + u8 TXPowercount; + bool bTXPowerTrackingInit; + bool bTXPowerTracking; + u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */ + u8 TM_Trigger; + u8 InternalPA5G[2]; /* pathA / pathB */ + + u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ + u8 ThermalValue; + u8 ThermalValue_LCK; + u8 ThermalValue_IQK; + u8 ThermalValue_DPK; + u8 ThermalValue_AVG[AVG_THERMAL_NUM]; + u8 ThermalValue_AVG_index; + u8 ThermalValue_RxGain; + u8 ThermalValue_Crystal; + u8 ThermalValue_DPKstore; + u8 ThermalValue_DPKtrack; + bool TxPowerTrackingInProgress; + bool bDPKenable; + + bool bReloadtxpowerindex; + u8 bRfPiEnable; + u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ + + u8 bCCKinCH14; + u8 CCK_index; + u8 OFDM_index[2]; + bool bDoneTxpower; + + u8 ThermalValue_HP[HP_THERMAL_NUM]; + u8 ThermalValue_HP_index; + struct iqk_matrix_regs_set IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; + + u8 Delta_IQK; + u8 Delta_LCK; + + /* for IQK */ + u32 RegC04; + u32 Reg874; + u32 RegC08; + u32 RegB68; + u32 RegB6C; + u32 Reg870; + u32 Reg860; + u32 Reg864; + + bool bIQKInitialized; + bool bLCKInProgress; + bool bAntennaDetected; + u32 ADDA_backup[IQK_ADDA_REG_NUM]; + u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; + u32 IQK_BB_backup_recover[9]; + u32 IQK_BB_backup[IQK_BB_REG_NUM]; + + /* for APK */ + u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ + u8 bAPKdone; + u8 bAPKThermalMeterIgnore; + u8 bDPdone; + u8 bDPPathAOK; + u8 bDPPathBOK; +}; + +/* ODM Dynamic common info value definition */ +struct odm_fat_t { + u8 Bssid[6]; + u8 antsel_rx_keep_0; + u8 antsel_rx_keep_1; + u8 antsel_rx_keep_2; + u32 antSumRSSI[7]; + u32 antRSSIcnt[7]; + u32 antAveRSSI[7]; + u8 FAT_State; + u32 TrainIdx; + u8 antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; + u8 antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; + u8 antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; + u32 MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u32 AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u32 MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u32 AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u8 RxIdleAnt; + bool bBecomeLinked; +}; + +enum fat_state { + FAT_NORMAL_STATE = 0, + FAT_TRAINING_STATE = 1, +}; + +enum ant_dif_type { + NO_ANTDIV = 0xFF, + CG_TRX_HW_ANTDIV = 0x01, + CGCS_RX_HW_ANTDIV = 0x02, + FIXED_HW_ANTDIV = 0x03, + CG_TRX_SMART_ANTDIV = 0x04, + CGCS_RX_SW_ANTDIV = 0x05, +}; + +/* 2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. */ +struct dm_odm_t { + /* struct timer_list FastAntTrainingTimer; */ + /* */ + /* Add for different team use temporarily */ + /* */ + struct rtw_adapter *Adapter; /* For CE/NIC team */ + struct rtl8723a_priv *priv; /* For AP/ADSL team */ + /* WHen you use Adapter or priv pointer, you must make sure the pointer is ready. */ + bool odm_ready; + + struct rtl8723a_priv fake_priv; + + u64 DebugComponents; + u32 DebugLevel; + +/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ + bool bCckHighPower; + u8 RFPathRxEnable; /* ODM_CMNINFO_RFPATH_ENABLE */ + u8 ControlChannel; +/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ + +/* 1 COMMON INFORMATION */ + + /* Init Value */ +/* HOOK BEFORE REG INIT----------- */ + /* ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ¡K¡K = 1/2/3/¡K */ + u32 SupportAbility; + /* ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 */ + u8 SupportInterface; + /* ODM composite or independent. Bit oriented/ 92C+92D+ .... or any other type = 1/2/3/... */ + u32 SupportICType; + /* Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */ + u8 CutVersion; + /* Fab Version TSMC/UMC = 0/1 */ + u8 FabVersion; + /* RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */ + u8 RFType; + /* Board Type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/... */ + u8 BoardType; + /* with external LNA NO/Yes = 0/1 */ + u8 ExtLNA; + /* with external PA NO/Yes = 0/1 */ + u8 ExtPA; + /* with external TRSW NO/Yes = 0/1 */ + u8 ExtTRSW; + u8 PatchID; /* Customer ID */ + bool bInHctTest; + bool bWIFITest; + + bool bDualMacSmartConcurrent; + u32 BK_SupportAbility; + u8 AntDivType; +/* HOOK BEFORE REG INIT----------- */ + + /* */ + /* Dynamic Value */ + /* */ +/* POINTER REFERENCE----------- */ + + u8 u8_temp; + bool bool_temp; + struct rtw_adapter *PADAPTER_temp; + + /* MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */ + u8 *pMacPhyMode; + /* TX Unicast byte count */ + u64 *pNumTxBytesUnicast; + /* RX Unicast byte count */ + u64 *pNumRxBytesUnicast; + /* Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */ + u8 *pWirelessMode; /* enum odm_wireless_mode */ + /* Frequence band 2.4G/5G = 0/1 */ + u8 *pBandType; + /* Secondary channel offset don't_care/below/above = 0/1/2 */ + u8 *pSecChOffset; + /* Security mode Open/WEP/AES/TKIP = 0/1/2/3 */ + u8 *pSecurity; + /* BW info 20M/40M/80M = 0/1/2 */ + u8 *pBandWidth; + /* Central channel location Ch1/Ch2/.... */ + u8 *pChannel; /* central channel number */ + /* Common info for 92D DMSP */ + + bool *pbGetValueFromOtherMac; + struct rtw_adapter **pBuddyAdapter; + bool *pbMasterOfDMSP; /* MAC0: master, MAC1: slave */ + /* Common info for Status */ + bool *pbScanInProcess; + bool *pbPowerSaving; + /* CCA Path 2-path/path-A/path-B = 0/1/2; using enum odm_cca_path. */ + u8 *pOnePathCCA; + /* pMgntInfo->AntennaTest */ + u8 *pAntennaTest; + bool *pbNet_closed; +/* POINTER REFERENCE----------- */ + /* */ +/* CALL BY VALUE------------- */ + bool bWIFI_Direct; + bool bWIFI_Display; + bool bLinked; + u8 RSSI_Min; + u8 InterfaceIndex; /* Add for 92D dual MAC: 0--Mac0 1--Mac1 */ + bool bIsMPChip; + bool bOneEntryOnly; + /* Common info for BTDM */ + bool bBtDisabled; /* BT is disabled */ + bool bBtHsOperation; /* BT HS mode is under progress */ + u8 btHsDigVal; /* use BT rssi to decide the DIG value */ + bool bBtDisableEdcaTurbo; /* Under some condition, don't enable the EDCA Turbo */ + bool bBtBusy; /* BT is busy. */ +/* CALL BY VALUE------------- */ + + /* 2 Define STA info. */ + /* _ODM_STA_INFO */ + /* 2012/01/12 MH For MP, we need to reduce one array pointer for default port.?? */ + struct sta_info * pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM]; + + /* */ + /* 2012/02/14 MH Add to share 88E ra with other SW team. */ + /* We need to colelct all support abilit to a proper area. */ + /* */ + bool RaSupport88E; + + /* Define ........... */ + + /* Latest packet phy info (ODM write) */ + struct odm_phy_dbg_info PhyDbgInfo; + /* PHY_INFO_88E PhyInfo; */ + + /* Latest packet phy info (ODM write) */ + struct odm_mac_info *pMacInfo; + /* MAC_INFO_88E MacInfo; */ + + /* Different Team independt structure?? */ + + /* */ + /* TX_RTP_CMN TX_retrpo; */ + /* TX_RTP_88E TX_retrpo; */ + /* TX_RTP_8195 TX_retrpo; */ + + /* */ + /* ODM Structure */ + /* */ + struct odm_fat_t DM_FatTable; + struct dig_t DM_DigTable; + struct dynamic_pwr_sav DM_PSTable; + struct pri_cca DM_PriCCA; + struct rx_hp DM_RXHP_Table; + struct false_alarm_stats FalseAlmCnt; + struct false_alarm_stats FlaseAlmCntBuddyAdapter; + struct sw_ant_sw DM_SWAT_Table; + bool RSSI_test; + + struct edca_turbo DM_EDCA_Table; + u32 WMMEDCA_BE; + /* Copy from SD4 structure */ + /* */ + /* ================================================== */ + /* */ + + /* common */ + bool *pbDriverStopped; + bool *pbDriverIsGoingToPnpSetPowerSleep; + bool *pinit_adpt_in_progress; + + /* PSD */ + bool bUserAssignLevel; + struct timer_list PSDTimer; + u8 RSSI_BT; /* come from BT */ + bool bPSDinProcess; + bool bDMInitialGainEnable; + + /* for rate adaptive, in fact, 88c/92c fw will handle this */ + u8 bUseRAMask; + + struct odm_rate_adapt RateAdaptive; + + + struct odm_rf_cal_t RFCalibrateInfo; + + /* */ + /* TX power tracking */ + /* */ + u8 BbSwingIdxOfdm; + u8 BbSwingIdxOfdmCurrent; + u8 BbSwingIdxOfdmBase; + bool BbSwingFlagOfdm; + u8 BbSwingIdxCck; + u8 BbSwingIdxCckCurrent; + u8 BbSwingIdxCckBase; + bool BbSwingFlagCck; + /* */ + /* ODM system resource. */ + /* */ + + /* ODM relative time. */ + struct timer_list PathDivSwitchTimer; + /* 2011.09.27 add for Path Diversity */ + struct timer_list CCKPathDiversityTimer; + struct timer_list FastAntTrainingTimer; + + /* ODM relative workitem. */ +}; /* DM_Dynamic_Mechanism_Structure */ + +enum odm_rf_content { + odm_radioa_txt = 0x1000, + odm_radiob_txt = 0x1001, + odm_radioc_txt = 0x1002, + odm_radiod_txt = 0x1003 +}; + +enum odm_bb_config_type { + CONFIG_BB_PHY_REG, + CONFIG_BB_AGC_TAB, + CONFIG_BB_AGC_TAB_2G, + CONFIG_BB_AGC_TAB_5G, + CONFIG_BB_PHY_REG_PG, +}; + +/* Status code */ +enum rt_status { + RT_STATUS_SUCCESS, + RT_STATUS_FAILURE, + RT_STATUS_PENDING, + RT_STATUS_RESOURCE, + RT_STATUS_INVALID_CONTEXT, + RT_STATUS_INVALID_PARAMETER, + RT_STATUS_NOT_SUPPORT, + RT_STATUS_OS_API_FAILED, +}; + +/* include "odm_function.h" */ + +/* 3=========================================================== */ +/* 3 DIG */ +/* 3=========================================================== */ + +enum dm_dig_op { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_SCAN_RSSI_TH 0x14 /* scan return issue for LC */ + + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX_NIC 0x4e +#define DM_DIG_MIN_NIC 0x1e + +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_MIN_AP 0x20 + +#define DM_DIG_MAX_NIC_HP 0x46 +#define DM_DIG_MIN_NIC_HP 0x2e + +#define DM_DIG_MAX_AP_HP 0x42 +#define DM_DIG_MIN_AP_HP 0x30 + +/* vivi 92c&92d has different definition, 20110504 */ +/* this is for 92c */ +#define DM_DIG_FA_TH0 0x200 +#define DM_DIG_FA_TH1 0x300 +#define DM_DIG_FA_TH2 0x400 +/* this is for 92d */ +#define DM_DIG_FA_TH0_92D 0x100 +#define DM_DIG_FA_TH1_92D 0x400 +#define DM_DIG_FA_TH2_92D 0x600 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +/* 3=========================================================== */ +/* 3 AGC RX High Power Mode */ +/* 3=========================================================== */ +#define LNA_Low_Gain_1 0x64 +#define LNA_Low_Gain_2 0x5A +#define LNA_Low_Gain_3 0x58 + +#define FA_RXHP_TH1 5000 +#define FA_RXHP_TH2 1500 +#define FA_RXHP_TH3 800 +#define FA_RXHP_TH4 600 +#define FA_RXHP_TH5 500 + +/* 3=========================================================== */ +/* 3 EDCA */ +/* 3=========================================================== */ + +/* 3=========================================================== */ +/* 3 Dynamic Tx Power */ +/* 3=========================================================== */ +/* Dynamic Tx Power Control Threshold */ +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F + +#define TxHighPwrLevel_Normal 0 +#define TxHighPwrLevel_Level1 1 +#define TxHighPwrLevel_Level2 2 +#define TxHighPwrLevel_BT1 3 +#define TxHighPwrLevel_BT2 4 +#define TxHighPwrLevel_15 5 +#define TxHighPwrLevel_35 6 +#define TxHighPwrLevel_50 7 +#define TxHighPwrLevel_70 8 +#define TxHighPwrLevel_100 9 + +/* 3=========================================================== */ +/* 3 Rate Adaptive */ +/* 3=========================================================== */ +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 + +/* 3=========================================================== */ +/* 3 BB Power Save */ +/* 3=========================================================== */ + + +enum dm_1r_cca { + CCA_1R =0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf_def { + RF_Save =0, + RF_Normal = 1, + RF_MAX = 2, +}; + +/* 3=========================================================== */ +/* 3 Antenna Diversity */ +/* 3=========================================================== */ +enum dm_swas { + Antenna_A = 1, + Antenna_B = 2, + Antenna_MAX = 3, +}; + +/* Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */ +#define MAX_ANTENNA_DETECTION_CNT 10 + +/* */ +/* Extern Global Variables. */ +/* */ +#define OFDM_TABLE_SIZE_92C 37 +#define OFDM_TABLE_SIZE_92D 43 +#define CCK_TABLE_SIZE 33 + +extern u32 OFDMSwingTable23A[OFDM_TABLE_SIZE_92D]; +extern u8 CCKSwingTable_Ch1_Ch1323A[CCK_TABLE_SIZE][8]; +extern u8 CCKSwingTable_Ch1423A [CCK_TABLE_SIZE][8]; + + + +/* */ +/* check Sta pointer valid or not */ +/* */ +#define IS_STA_VALID(pSta) (pSta) +/* 20100514 Joseph: Add definition for antenna switching test after link. */ +/* This indicates two different the steps. */ +/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */ +/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */ +/* with original RSSI to determine if it is necessary to switch antenna. */ +#define SWAW_STEP_PEAK 0 +#define SWAW_STEP_DETERMINE 1 + +void ODM_Write_DIG23a(struct dm_odm_t *pDM_Odm, u8 CurrentIGI); +void ODM_Write_CCK_CCA_Thres23a(struct dm_odm_t *pDM_Odm, u8 CurCCK_CCAThres); + +void ODM_SetAntenna(struct dm_odm_t *pDM_Odm, u8 Antenna); + + +#define dm_RF_Saving ODM_RF_Saving23a +void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal); + +#define SwAntDivRestAfterLink ODM_SwAntDivRestAfterLink +void ODM_SwAntDivRestAfterLink(struct dm_odm_t *pDM_Odm); + +#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck23a +void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm); + +bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate, + u8 *pRATRState); + + +#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi +void ODM_SwAntDivChkPerPktRssi(struct dm_odm_t *pDM_Odm, u8 StationID, + struct odm_phy_info *pPhyInfo); + +u32 ConvertTo_dB23a(u32 Value); + +u32 GetPSDData(struct dm_odm_t *pDM_Odm, unsigned int point, u8 initial_gain_psd); + +void odm_DIG23abyRSSI_LPS(struct dm_odm_t *pDM_Odm); + +u32 ODM_Get_Rate_Bitmap23a(struct dm_odm_t *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level); + + +void ODM23a_DMInit(struct dm_odm_t *pDM_Odm); + +void ODM_DMWatchdog23a(struct dm_odm_t *pDM_Odm); /* For common use in the future */ + +void ODM_CmnInfoInit23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo CmnInfo, u32 Value); + +void ODM23a_CmnInfoHook(struct dm_odm_t *pDM_Odm, enum odm_cmninfo CmnInfo, void *pValue); + +void ODM_CmnInfoPtrArrayHook23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo CmnInfo, u16 Index, void *pValue); + +void ODM_CmnInfoUpdate23a(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value); + +void ODM_InitAllTimers(struct dm_odm_t *pDM_Odm); + +void ODM_CancelAllTimers(struct dm_odm_t *pDM_Odm); + +void ODM_ReleaseAllTimers(struct dm_odm_t *pDM_Odm); + +void ODM_ResetIQKResult(struct dm_odm_t *pDM_Odm); + +void ODM_AntselStatistics_88C(struct dm_odm_t *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate); + +void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm); + +bool ODM_SingleDualAntennaDetection(struct dm_odm_t *pDM_Odm, u8 mode); + +void odm_dtc(struct dm_odm_t *pDM_Odm); + +#endif diff --git a/drivers/staging/rtl8723au/include/odm_HWConfig.h b/drivers/staging/rtl8723au/include/odm_HWConfig.h new file mode 100644 index 000000000000..057fdb012a47 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_HWConfig.h @@ -0,0 +1,174 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + + +#ifndef __HALHWOUTSRC_H__ +#define __HALHWOUTSRC_H__ + +#include + +/* */ +/* Definition */ +/* */ +/* */ +/* */ +/* CCK Rates, TxHT = 0 */ +#define DESC92C_RATE1M 0x00 +#define DESC92C_RATE2M 0x01 +#define DESC92C_RATE5_5M 0x02 +#define DESC92C_RATE11M 0x03 + +/* OFDM Rates, TxHT = 0 */ +#define DESC92C_RATE6M 0x04 +#define DESC92C_RATE9M 0x05 +#define DESC92C_RATE12M 0x06 +#define DESC92C_RATE18M 0x07 +#define DESC92C_RATE24M 0x08 +#define DESC92C_RATE36M 0x09 +#define DESC92C_RATE48M 0x0a +#define DESC92C_RATE54M 0x0b + +/* MCS Rates, TxHT = 1 */ +#define DESC92C_RATEMCS0 0x0c +#define DESC92C_RATEMCS1 0x0d +#define DESC92C_RATEMCS2 0x0e +#define DESC92C_RATEMCS3 0x0f +#define DESC92C_RATEMCS4 0x10 +#define DESC92C_RATEMCS5 0x11 +#define DESC92C_RATEMCS6 0x12 +#define DESC92C_RATEMCS7 0x13 +#define DESC92C_RATEMCS8 0x14 +#define DESC92C_RATEMCS9 0x15 +#define DESC92C_RATEMCS10 0x16 +#define DESC92C_RATEMCS11 0x17 +#define DESC92C_RATEMCS12 0x18 +#define DESC92C_RATEMCS13 0x19 +#define DESC92C_RATEMCS14 0x1a +#define DESC92C_RATEMCS15 0x1b +#define DESC92C_RATEMCS15_SG 0x1c +#define DESC92C_RATEMCS32 0x20 + + +/* */ +/* structure and define */ +/* */ + +struct phy_rx_agc_info { + #ifdef __LITTLE_ENDIAN + u8 gain:7,trsw:1; + #else + u8 trsw:1,gain:7; + #endif +}; + +struct phy_status_rpt { + struct phy_rx_agc_info path_agc[2]; + u8 ch_corr[2]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_rpt_b_ofdm_cfosho_b; + u8 rsvd_1;/* ch_corr_msb; */ + u8 noise_power_db_msb; + u8 path_cfotail[2]; + u8 pcts_mask[2]; + s8 stream_rxevm[2]; + u8 path_rxsnr[2]; + u8 noise_power_db_lsb; + u8 rsvd_2[3]; + u8 stream_csi[2]; + u8 stream_target_csi[2]; + s8 sig_evm; + u8 rsvd_3; + +#ifdef __LITTLE_ENDIAN + u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ + u8 sgi_en:1; + u8 rxsc:2; + u8 idle_long:1; + u8 r_ant_train_en:1; + u8 ant_sel_b:1; + u8 ant_sel:1; +#else /* _BIG_ENDIAN_ */ + u8 ant_sel:1; + u8 ant_sel_b:1; + u8 r_ant_train_en:1; + u8 idle_long:1; + u8 rxsc:2; + u8 sgi_en:1; + u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ +#endif +}; + + +struct phy_status_rpt_8195 { + struct phy_rx_agc_info path_agc[2]; + u8 ch_num[2]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_bb_pwr_ofdm_cfosho_b; + u8 cck_rx_path; /* CCK_RX_PATH [3:0] (with regA07[3:0] definition) */ + u8 rsvd_1; + u8 path_cfotail[2]; + u8 pcts_mask[2]; + s8 stream_rxevm[2]; + u8 path_rxsnr[2]; + u8 rsvd_2[2]; + u8 stream_snr[2]; + u8 stream_csi[2]; + u8 rsvd_3[2]; + s8 sig_evm; + u8 rsvd_4; +#ifdef __LITTLE_ENDIAN + u8 antidx_anta:3; + u8 antidx_antb:3; + u8 rsvd_5:2; +#else /* _BIG_ENDIAN_ */ + u8 rsvd_5:2; + u8 antidx_antb:3; + u8 antidx_anta:3; +#endif +}; + + +void odm_Init_RSSIForDM23a(struct dm_odm_t *pDM_Odm); + +void +ODM_PhyStatusQuery23a( + struct dm_odm_t *pDM_Odm, + struct odm_phy_info *pPhyInfo, + u8 * pPhyStatus, + struct odm_packet_info *pPktinfo + ); + +void ODM_MacStatusQuery23a(struct dm_odm_t *pDM_Odm, + u8 *pMacStatus, + u8 MacID, + bool bPacketMatchBSSID, + bool bPacketToSelf, + bool bPacketBeacon +); + +enum hal_status ODM_ConfigRFWithHeaderFile23a(struct dm_odm_t *pDM_Odm, + enum RF_RADIO_PATH Content, + enum RF_RADIO_PATH eRFPath +); + +enum hal_status ODM_ConfigBBWithHeaderFile23a(struct dm_odm_t *pDM_Odm, + enum odm_bb_config_type ConfigType +); + +enum hal_status ODM_ConfigMACWithHeaderFile23a(struct dm_odm_t *pDM_Odm); + +#endif diff --git a/drivers/staging/rtl8723au/include/odm_RegConfig8723A.h b/drivers/staging/rtl8723au/include/odm_RegConfig8723A.h new file mode 100644 index 000000000000..4ea579b2e8bd --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_RegConfig8723A.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __INC_ODM_REGCONFIG_H_8723A +#define __INC_ODM_REGCONFIG_H_8723A + +void odm_ConfigRFReg_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data, + enum RF_RADIO_PATH RF_PATH, u32 RegAddr); + +void odm_ConfigRF_RadioA_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data); + +void odm_ConfigRF_RadioB_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data); + +void odm_ConfigMAC_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u8 Data); + +void odm_ConfigBB_AGC_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, + u32 Bitmask, u32 Data); + +void odm_ConfigBB_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data); + +void odm_ConfigBB_PHY_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data); + +#endif /* end of SUPPORT */ diff --git a/drivers/staging/rtl8723au/include/odm_RegDefine11AC.h b/drivers/staging/rtl8723au/include/odm_RegDefine11AC.h new file mode 100644 index 000000000000..77b7acec5ea8 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_RegDefine11AC.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef __ODM_REGDEFINE11AC_H__ +#define __ODM_REGDEFINE11AC_H__ + +/* 2 RF REG LIST */ + + + +/* 2 BB REG LIST */ +/* PAGE 8 */ +/* PAGE 9 */ +#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 +/* PAGE A */ +#define ODM_REG_CCK_CCA_11AC 0xA0A +#define ODM_REG_CCK_FA_RST_11AC 0xA2C +#define ODM_REG_CCK_FA_11AC 0xA5C +/* PAGE C */ +#define ODM_REG_IGI_A_11AC 0xC50 +/* PAGE E */ +#define ODM_REG_IGI_B_11AC 0xE50 +/* PAGE F */ +#define ODM_REG_OFDM_FA_11AC 0xF48 + + +/* 2 MAC REG LIST */ + + + + +/* DIG Related */ +#define ODM_BIT_IGI_11AC 0xFFFFFFFF + + + +#endif diff --git a/drivers/staging/rtl8723au/include/odm_RegDefine11N.h b/drivers/staging/rtl8723au/include/odm_RegDefine11N.h new file mode 100644 index 000000000000..27782154f502 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_RegDefine11N.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef __ODM_REGDEFINE11N_H__ +#define __ODM_REGDEFINE11N_H__ + + +/* 2 RF REG LIST */ +#define ODM_REG_RF_MODE_11N 0x00 +#define ODM_REG_RF_0B_11N 0x0B +#define ODM_REG_CHNBW_11N 0x18 +#define ODM_REG_T_METER_11N 0x24 +#define ODM_REG_RF_25_11N 0x25 +#define ODM_REG_RF_26_11N 0x26 +#define ODM_REG_RF_27_11N 0x27 +#define ODM_REG_RF_2B_11N 0x2B +#define ODM_REG_RF_2C_11N 0x2C +#define ODM_REG_RXRF_A3_11N 0x3C +#define ODM_REG_T_METER_92D_11N 0x42 +#define ODM_REG_T_METER_88E_11N 0x42 + + + +/* 2 BB REG LIST */ +/* PAGE 8 */ +#define ODM_REG_BB_CTRL_11N 0x800 +#define ODM_REG_RF_PIN_11N 0x804 +#define ODM_REG_PSD_CTRL_11N 0x808 +#define ODM_REG_TX_ANT_CTRL_11N 0x80C +#define ODM_REG_BB_PWR_SAV5_11N 0x818 +#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 +#define ODM_REG_RX_DEFUALT_A_11N 0x858 +#define ODM_REG_RX_DEFUALT_B_11N 0x85A +#define ODM_REG_BB_PWR_SAV3_11N 0x85C +#define ODM_REG_ANTSEL_CTRL_11N 0x860 +#define ODM_REG_RX_ANT_CTRL_11N 0x864 +#define ODM_REG_PIN_CTRL_11N 0x870 +#define ODM_REG_BB_PWR_SAV1_11N 0x874 +#define ODM_REG_ANTSEL_PATH_11N 0x878 +#define ODM_REG_BB_3WIRE_11N 0x88C +#define ODM_REG_SC_CNT_11N 0x8C4 +#define ODM_REG_PSD_DATA_11N 0x8B4 +/* PAGE 9 */ +#define ODM_REG_ANT_MAPPING1_11N 0x914 +#define ODM_REG_ANT_MAPPING2_11N 0x918 +/* PAGE A */ +#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 +#define ODM_REG_CCK_CCA_11N 0xA0A +#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C +#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 +#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 +#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 +#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 +#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 +#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 +#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 +#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 +#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 +#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 +#define ODM_REG_CCK_FA_RST_11N 0xA2C +#define ODM_REG_CCK_FA_MSB_11N 0xA58 +#define ODM_REG_CCK_FA_LSB_11N 0xA5C +#define ODM_REG_CCK_CCA_CNT_11N 0xA60 +#define ODM_REG_BB_PWR_SAV4_11N 0xA74 +/* PAGE B */ +#define ODM_REG_LNA_SWITCH_11N 0xB2C +#define ODM_REG_PATH_SWITCH_11N 0xB30 +#define ODM_REG_RSSI_CTRL_11N 0xB38 +#define ODM_REG_CONFIG_ANTA_11N 0xB68 +#define ODM_REG_RSSI_BT_11N 0xB9C +/* PAGE C */ +#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 +#define ODM_REG_RX_PATH_11N 0xC04 +#define ODM_REG_TRMUX_11N 0xC08 +#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C +#define ODM_REG_RXIQI_MATRIX_11N 0xC14 +#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C +#define ODM_REG_IGI_A_11N 0xC50 +#define ODM_REG_ANTDIV_PARA2_11N 0xC54 +#define ODM_REG_IGI_B_11N 0xC58 +#define ODM_REG_ANTDIV_PARA3_11N 0xC5C +#define ODM_REG_BB_PWR_SAV2_11N 0xC70 +#define ODM_REG_RX_OFF_11N 0xC7C +#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 +#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 +#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 +#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C +#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 +#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 +#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 +/* PAGE D */ +#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 +#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 +#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 +#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 +/* PAGE E */ +#define ODM_REG_TXAGC_A_6_18_11N 0xE00 +#define ODM_REG_TXAGC_A_24_54_11N 0xE04 +#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 +#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 +#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 +#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 +#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C +#define ODM_REG_FPGA0_IQK_11N 0xE28 +#define ODM_REG_TXIQK_TONE_A_11N 0xE30 +#define ODM_REG_RXIQK_TONE_A_11N 0xE34 +#define ODM_REG_TXIQK_PI_A_11N 0xE38 +#define ODM_REG_RXIQK_PI_A_11N 0xE3C +#define ODM_REG_TXIQK_11N 0xE40 +#define ODM_REG_RXIQK_11N 0xE44 +#define ODM_REG_IQK_AGC_PTS_11N 0xE48 +#define ODM_REG_IQK_AGC_RSP_11N 0xE4C +#define ODM_REG_BLUETOOTH_11N 0xE6C +#define ODM_REG_RX_WAIT_CCA_11N 0xE70 +#define ODM_REG_TX_CCK_RFON_11N 0xE74 +#define ODM_REG_TX_CCK_BBON_11N 0xE78 +#define ODM_REG_OFDM_RFON_11N 0xE7C +#define ODM_REG_OFDM_BBON_11N 0xE80 +#define ODM_REG_TX2RX_11N 0xE84 +#define ODM_REG_TX2TX_11N 0xE88 +#define ODM_REG_RX_CCK_11N 0xE8C +#define ODM_REG_RX_OFDM_11N 0xED0 +#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 +#define ODM_REG_RX2RX_11N 0xED8 +#define ODM_REG_STANDBY_11N 0xEDC +#define ODM_REG_SLEEP_11N 0xEE0 +#define ODM_REG_PMPD_ANAEN_11N 0xEEC + + + + + + + +/* 2 MAC REG LIST */ +#define ODM_REG_BB_RST_11N 0x02 +#define ODM_REG_ANTSEL_PIN_11N 0x4C +#define ODM_REG_EARLY_MODE_11N 0x4D0 +#define ODM_REG_RSSI_MONITOR_11N 0x4FE +#define ODM_REG_EDCA_VO_11N 0x500 +#define ODM_REG_EDCA_VI_11N 0x504 +#define ODM_REG_EDCA_BE_11N 0x508 +#define ODM_REG_EDCA_BK_11N 0x50C +#define ODM_REG_TXPAUSE_11N 0x522 +#define ODM_REG_RESP_TX_11N 0x6D8 +#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 +#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 + + +/* DIG Related */ +#define ODM_BIT_IGI_11N 0x0000007F + +#endif diff --git a/drivers/staging/rtl8723au/include/odm_debug.h b/drivers/staging/rtl8723au/include/odm_debug.h new file mode 100644 index 000000000000..5bc51d09e52f --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_debug.h @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + + +#ifndef __ODM_DBG_H__ +#define __ODM_DBG_H__ + + +/* */ +/* Define the debug levels */ +/* */ +/* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */ +/* So that, they can help SW engineer to develope or trace states changed */ +/* and also help HW enginner to trace every operation to and from HW, */ +/* e.g IO, Tx, Rx. */ +/* */ +/* 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */ +/* which help us to debug SW or HW. */ +/* */ +/* */ +/* */ +/* Never used in a call to ODM_RT_TRACE()! */ +/* */ +#define ODM_DBG_OFF 1 + +/* */ +/* Fatal bug. */ +/* For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */ +/* resource allocation failed, unexpected HW behavior, HW BUG and so on. */ +/* */ +#define ODM_DBG_SERIOUS 2 + +/* */ +/* Abnormal, rare, or unexpeted cases. */ +/* For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */ +/* */ +#define ODM_DBG_WARNING 3 + +/* */ +/* Normal case with useful information about current SW or HW state. */ +/* For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, */ +/* SW protocol state change, dynamic mechanism state change and so on. */ +/* */ +#define ODM_DBG_LOUD 4 + +/* */ +/* Normal case with detail execution flow or information. */ +/* */ +#define ODM_DBG_TRACE 5 + +/* */ +/* Define the tracing components */ +/* */ +/* */ +/* BB Functions */ +#define ODM_COMP_DIG BIT0 +#define ODM_COMP_RA_MASK BIT1 +#define ODM_COMP_DYNAMIC_TXPWR BIT2 +#define ODM_COMP_FA_CNT BIT3 +#define ODM_COMP_RSSI_MONITOR BIT4 +#define ODM_COMP_CCK_PD BIT5 +#define ODM_COMP_ANT_DIV BIT6 +#define ODM_COMP_PWR_SAVE BIT7 +#define ODM_COMP_PWR_TRAIN BIT8 +#define ODM_COMP_RATE_ADAPTIVE BIT9 +#define ODM_COMP_PATH_DIV BIT10 +#define ODM_COMP_PSD BIT11 +#define ODM_COMP_DYNAMIC_PRICCA BIT12 +#define ODM_COMP_RXHP BIT13 +/* MAC Functions */ +#define ODM_COMP_EDCA_TURBO BIT16 +#define ODM_COMP_EARLY_MODE BIT17 +/* RF Functions */ +#define ODM_COMP_TX_PWR_TRACK BIT24 +#define ODM_COMP_RX_GAIN_TRACK BIT25 +#define ODM_COMP_CALIBRATION BIT26 +/* Common Functions */ +#define ODM_COMP_COMMON BIT30 +#define ODM_COMP_INIT BIT31 + +/*------------------------Export Macro Definition---------------------------*/ + #define DbgPrint printk + #define RT_PRINTK(fmt, args...) DbgPrint("%s(): " fmt, __func__, ## args); + +#ifndef ASSERT + #define ASSERT(expr) +#endif + +#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ + { \ + DbgPrint("[ODM-8723A] "); \ + RT_PRINTK fmt; \ + } + +#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ + { \ + RT_PRINTK fmt; \ + } + +#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \ + if(!(expr)) { \ + DbgPrint("Assertion failed! %s at ......\n", #expr); \ + DbgPrint(" ......%s,%s,line=%d\n", __FILE__, __func__, __LINE__);\ + RT_PRINTK fmt; \ + ASSERT(false); \ + } +#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); } +#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); } +#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); } + +#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel){ \ + int __i; \ + u8 * __ptr = (u8 *)ptr; \ + DbgPrint("[ODM] "); \ + DbgPrint(title_str); \ + DbgPrint(" "); \ + for (__i=0; __i < 6; __i++) \ + DbgPrint("%02X%s", __ptr[__i], (__i == 5) ? "" : "-"); \ + DbgPrint("\n"); \ + } + +void ODM_InitDebugSetting23a(struct dm_odm_t *pDM_Odm); + +#endif /* __ODM_DBG_H__ */ diff --git a/drivers/staging/rtl8723au/include/odm_interface.h b/drivers/staging/rtl8723au/include/odm_interface.h new file mode 100644 index 000000000000..f216b5846f92 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_interface.h @@ -0,0 +1,131 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + + +#ifndef __ODM_INTERFACE_H__ +#define __ODM_INTERFACE_H__ + + + +/* */ +/* =========== Constant/Structure/Enum/... Define */ +/* */ + + + +/* */ +/* =========== Macro Define */ +/* */ + +#define _reg_all(_name) ODM_##_name +#define _reg_ic(_name, _ic) ODM_##_name##_ic +#define _bit_all(_name) BIT_##_name +#define _bit_ic(_name, _ic) BIT_##_name##_ic + +/* _cat: implemented by Token-Pasting Operator. */ + +/*=================================== + +#define ODM_REG_DIG_11N 0xC50 +#define ODM_REG_DIG_11AC 0xDDD + +ODM_REG(DIG,_pDM_Odm) +=====================================*/ + +#define _reg_11N(_name) ODM_REG_##_name##_11N +#define _reg_11AC(_name) ODM_REG_##_name##_11AC +#define _bit_11N(_name) ODM_BIT_##_name##_11N +#define _bit_11AC(_name) ODM_BIT_##_name##_11AC + +#define _cat(_name, _ic_type, _func) \ + ( \ + ((_ic_type) & ODM_IC_11N_SERIES)? _func##_11N(_name): \ + _func##_11AC(_name) \ + ) + +/* _name: name of register or bit. */ +/* Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */ +/* gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", depends on SupportICType. */ +#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) +#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) + +/* */ +/* 2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. */ +/* Suggest HW team to use thread instead of workitem. Windows also support the feature. */ +/* */ +typedef void (*RT_WORKITEM_CALL_BACK)(struct work_struct *pContext); + +/* */ +/* =========== Extern Variable ??? It should be forbidden. */ +/* */ + + +/* */ +/* =========== EXtern Function Prototype */ +/* */ + + +u8 ODM_Read1Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr); + +u16 ODM_Read2Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr); + +u32 ODM_Read4Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr); + +void ODM_Write1Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u8 Data); + +void ODM_Write2Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u16 Data); + +void ODM_Write4Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 Data); + +void ODM_SetMACReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data); + +u32 ODM_GetMACReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask); + +void ODM_SetBBReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data); + +u32 ODM_GetBBReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask); + +void ODM_SetRFReg(struct dm_odm_t *pDM_Odm, enum RF_RADIO_PATH eRFPath, + u32 RegAddr, u32 BitMask, u32 Data); + +u32 ODM_GetRFReg(struct dm_odm_t *pDM_Odm, enum RF_RADIO_PATH eRFPath, + u32 RegAddr, u32 BitMask); + +/* Memory Relative Function. */ +void ODM_AllocateMemory(struct dm_odm_t *pDM_Odm, void **pPtr, u32 length); +void ODM_FreeMemory(struct dm_odm_t *pDM_Odm, void *pPtr, u32 length); + +s32 ODM_CompareMemory(struct dm_odm_t *pDM_Odm, void *pBuf1, void *pBuf2, u32 length); + +/* ODM MISC-spin lock relative API. */ +void ODM_AcquireSpinLock(struct dm_odm_t *pDM_Odm, enum rt_spinlock_type type); + +void ODM_ReleaseSpinLock(struct dm_odm_t *pDM_Odm, enum rt_spinlock_type type); + +/* ODM MISC-workitem relative API. */ +void ODM_InitializeWorkItem(struct dm_odm_t *pDM_Odm, void *pRtWorkItem, + RT_WORKITEM_CALL_BACK RtWorkItemCallback, void *pContext, const char *szID); + +/* ODM Timer relative API. */ +void ODM_SetTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer, u32 msDelay); + +void ODM_ReleaseTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer); + +/* ODM FW relative API. */ +u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum, + u32 *pElementID, u32 *pCmdLen, u8 **pCmbBuffer, + u8 *CmdStartSeq); + +#endif /* __ODM_INTERFACE_H__ */ diff --git a/drivers/staging/rtl8723au/include/odm_precomp.h b/drivers/staging/rtl8723au/include/odm_precomp.h new file mode 100644 index 000000000000..f3fc2fad9884 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_precomp.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef __ODM_PRECOMP_H__ +#define __ODM_PRECOMP_H__ + +#include "odm_types.h" + +#define TEST_FALG___ 1 + +/* 2 Config Flags and Structs - defined by each ODM Type */ + +#include +#include +#include + + +/* 2 Hardware Parameter Files */ +#include "Hal8723UHWImg_CE.h" + + +/* 2 OutSrc Header Files */ + +#include "odm.h" +#include "odm_HWConfig.h" +#include "odm_debug.h" +#include "odm_RegDefine11AC.h" +#include "odm_RegDefine11N.h" + +#include "HalDMOutSrc8723A.h" /* for IQK,LCK,Power-tracking */ +#include "rtl8723a_hal.h" + +#include "odm_interface.h" +#include "odm_reg.h" + +#include "HalHWImg8723A_MAC.h" +#include "HalHWImg8723A_RF.h" +#include "HalHWImg8723A_BB.h" +#include "HalHWImg8723A_FW.h" +#include "odm_RegConfig8723A.h" + +#endif /* __ODM_PRECOMP_H__ */ diff --git a/drivers/staging/rtl8723au/include/odm_reg.h b/drivers/staging/rtl8723au/include/odm_reg.h new file mode 100644 index 000000000000..56191e9fdcdb --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_reg.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +/* */ +/* File Name: odm_reg.h */ +/* */ +/* Description: */ +/* */ +/* This file is for general register definition. */ +/* */ +/* */ +/* */ +#ifndef __HAL_ODM_REG_H__ +#define __HAL_ODM_REG_H__ + +/* */ +/* Register Definition */ +/* */ + +/* MAC REG */ +#define ODM_BB_RESET 0x002 +#define ODM_DUMMY 0x4fe +#define ODM_EDCA_VO_PARAM 0x500 +#define ODM_EDCA_VI_PARAM 0x504 +#define ODM_EDCA_BE_PARAM 0x508 +#define ODM_EDCA_BK_PARAM 0x50C +#define ODM_TXPAUSE 0x522 + +/* BB REG */ +#define ODM_FPGA_PHY0_PAGE8 0x800 +#define ODM_PSD_SETTING 0x808 +#define ODM_AFE_SETTING 0x818 +#define ODM_TXAGC_B_6_18 0x830 +#define ODM_TXAGC_B_24_54 0x834 +#define ODM_TXAGC_B_MCS32_5 0x838 +#define ODM_TXAGC_B_MCS0_MCS3 0x83c +#define ODM_TXAGC_B_MCS4_MCS7 0x848 +#define ODM_TXAGC_B_MCS8_MCS11 0x84c +#define ODM_ANALOG_REGISTER 0x85c +#define ODM_RF_INTERFACE_OUTPUT 0x860 +#define ODM_TXAGC_B_MCS12_MCS15 0x868 +#define ODM_TXAGC_B_11_A_2_11 0x86c +#define ODM_AD_DA_LSB_MASK 0x874 +#define ODM_ENABLE_3_WIRE 0x88c +#define ODM_PSD_REPORT 0x8b4 +#define ODM_R_ANT_SELECT 0x90c +#define ODM_CCK_ANT_SELECT 0xa07 +#define ODM_CCK_PD_THRESH 0xa0a +#define ODM_CCK_RF_REG1 0xa11 +#define ODM_CCK_MATCH_FILTER 0xa20 +#define ODM_CCK_RAKE_MAC 0xa2e +#define ODM_CCK_CNT_RESET 0xa2d +#define ODM_CCK_TX_DIVERSITY 0xa2f +#define ODM_CCK_FA_CNT_MSB 0xa5b +#define ODM_CCK_FA_CNT_LSB 0xa5c +#define ODM_CCK_NEW_FUNCTION 0xa75 +#define ODM_OFDM_PHY0_PAGE_C 0xc00 +#define ODM_OFDM_RX_ANT 0xc04 +#define ODM_R_A_RXIQI 0xc14 +#define ODM_R_A_AGC_CORE1 0xc50 +#define ODM_R_A_AGC_CORE2 0xc54 +#define ODM_R_B_AGC_CORE1 0xc58 +#define ODM_R_AGC_PAR 0xc70 +#define ODM_R_HTSTF_AGC_PAR 0xc7c +#define ODM_TX_PWR_TRAINING_A 0xc90 +#define ODM_TX_PWR_TRAINING_B 0xc98 +#define ODM_OFDM_FA_CNT1 0xcf0 +#define ODM_OFDM_PHY0_PAGE_D 0xd00 +#define ODM_OFDM_FA_CNT2 0xda0 +#define ODM_OFDM_FA_CNT3 0xda4 +#define ODM_OFDM_FA_CNT4 0xda8 +#define ODM_TXAGC_A_6_18 0xe00 +#define ODM_TXAGC_A_24_54 0xe04 +#define ODM_TXAGC_A_1_MCS32 0xe08 +#define ODM_TXAGC_A_MCS0_MCS3 0xe10 +#define ODM_TXAGC_A_MCS4_MCS7 0xe14 +#define ODM_TXAGC_A_MCS8_MCS11 0xe18 +#define ODM_TXAGC_A_MCS12_MCS15 0xe1c + +/* RF REG */ +#define ODM_GAIN_SETTING 0x00 +#define ODM_CHANNEL 0x18 + +/* Ant Detect Reg */ +#define ODM_DPDT 0x300 + +/* PSD Init */ +#define ODM_PSDREG 0x808 + +/* 92D Path Div */ +#define PATHDIV_REG 0xB30 +#define PATHDIV_TRI 0xBA0 + + +/* */ +/* Bitmap Definition */ +/* */ + +#define BIT_FA_RESET BIT0 + + + +#endif diff --git a/drivers/staging/rtl8723au/include/odm_types.h b/drivers/staging/rtl8723au/include/odm_types.h new file mode 100644 index 000000000000..a866769ea178 --- /dev/null +++ b/drivers/staging/rtl8723au/include/odm_types.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __ODM_TYPES_H__ +#define __ODM_TYPES_H__ + +/* Define Different SW team support */ + +enum hal_status { + HAL_STATUS_SUCCESS, + HAL_STATUS_FAILURE, +}; + +enum rt_spinlock_type { + RT_TEMP =1, +}; + +#define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value) \ + SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value) +#define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value) \ + SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value) +#define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value) \ + SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value) + +#endif /* __ODM_TYPES_H__ */ diff --git a/drivers/staging/rtl8723au/include/osdep_intf.h b/drivers/staging/rtl8723au/include/osdep_intf.h new file mode 100644 index 000000000000..b603cf532900 --- /dev/null +++ b/drivers/staging/rtl8723au/include/osdep_intf.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef __OSDEP_INTF_H_ +#define __OSDEP_INTF_H_ + +#include +#include + +int rtw_hw_suspend23a(struct rtw_adapter *padapter); +int rtw_hw_resume23a(struct rtw_adapter *padapter); + +u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter); +u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter); +u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter); + +u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter); +void rtw_stop_drv_threads23a (struct rtw_adapter *padapter); +void rtw_cancel_all_timer23a(struct rtw_adapter *padapter); + +int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname); +struct net_device *rtw_init_netdev23a(struct rtw_adapter *padapter); + +u16 rtw_recv_select_queue23a(struct sk_buff *skb); + +void rtw_ips_dev_unload23a(struct rtw_adapter *padapter); + +int rtw_ips_pwr_up23a(struct rtw_adapter *padapter); +void rtw_ips_pwr_down23a(struct rtw_adapter *padapter); + +int rtw_drv_register_netdev(struct rtw_adapter *padapter); +void rtw_ndev_destructor(struct net_device *ndev); + +#endif /* _OSDEP_INTF_H_ */ diff --git a/drivers/staging/rtl8723au/include/osdep_service.h b/drivers/staging/rtl8723au/include/osdep_service.h new file mode 100644 index 000000000000..cb7b5cdcbe55 --- /dev/null +++ b/drivers/staging/rtl8723au/include/osdep_service.h @@ -0,0 +1,340 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __OSDEP_SERVICE_H_ +#define __OSDEP_SERVICE_H_ + +#define _FAIL 0 +#define _SUCCESS 1 +#define RTW_RX_HANDLED 2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Necessary because we use the proc fs */ +#include /* for struct tasklet_struct */ +#include +#include + + +/* #include */ +#include +#include +#include +#include + +struct rtw_adapter; +struct c2h_evt_hdr; + +typedef s32 (*c2h_id_filter)(u8 id); + +struct rtw_queue { + struct list_head queue; + spinlock_t lock; +}; + +static inline struct list_head *get_list_head(struct rtw_queue *queue) +{ + return (&queue->queue); +} + +static inline int rtw_netif_queue_stopped(struct net_device *pnetdev) +{ + return (netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) && + netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) && + netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) && + netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3)) ); +} + +#ifndef BIT +#define BIT(x) ( 1 << (x)) +#endif +static inline u32 CHKBIT(u32 x) +{ + WARN_ON(x >= 32); + if (x >= 32) + return 0; + return BIT(x); +} + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#define BIT32 0x0100000000 +#define BIT33 0x0200000000 +#define BIT34 0x0400000000 +#define BIT35 0x0800000000 +#define BIT36 0x1000000000 + +int RTW_STATUS_CODE23a(int error_code); + +u8* _rtw_vmalloc(u32 sz); +u8* _rtw_zvmalloc(u32 sz); +void _rtw_vmfree(u8 *pbuf, u32 sz); +#define rtw_vmalloc(sz) _rtw_vmalloc((sz)) +#define rtw_zvmalloc(sz) _rtw_zvmalloc((sz)) +#define rtw_vmfree(pbuf, sz) _rtw_vmfree((pbuf), (sz)) + +extern unsigned char REALTEK_96B_IE23A[]; +extern unsigned char MCS_rate_2R23A[16]; +extern unsigned char RTW_WPA_OUI23A[]; +extern unsigned char WPA_TKIP_CIPHER23A[4]; +extern unsigned char RSN_TKIP_CIPHER23A[4]; + +extern unsigned char MCS_rate_2R23A[16]; +extern unsigned char MCS_rate_1R23A[16]; + +void _rtw_init_queue23a(struct rtw_queue *pqueue); +u32 _rtw_queue_empty23a(struct rtw_queue *pqueue); + +u32 rtw_get_current_time(void); +u32 rtw_systime_to_ms23a(u32 systime); +u32 rtw_ms_to_systime23a(u32 ms); +s32 rtw_get_passing_time_ms23a(u32 start); +s32 rtw_get_time_interval_ms23a(u32 start, u32 end); + +#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) +#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2) + +static inline u32 _RND4(u32 sz) +{ + + u32 val; + + val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2; + + return val; + +} + +static inline u32 _RND8(u32 sz) +{ + + u32 val; + + val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3; + + return val; + +} + +static inline u32 _RND128(u32 sz) +{ + + u32 val; + + val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7; + + return val; + +} + +static inline u32 _RND256(u32 sz) +{ + + u32 val; + + val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8; + + return val; + +} + +static inline u32 _RND512(u32 sz) +{ + + u32 val; + + val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9; + + return val; + +} + +static inline u32 bitshift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) + if (((bitmask>>i) & 0x1) == 1) break; + + return i; +} + +#define STRUCT_PACKED __attribute__ ((packed)) + +/* limitation of path length */ +#define PATH_LENGTH_MAX PATH_MAX + +void rtw_suspend_lock_init(void); +void rtw_suspend_lock_uninit(void); +void rtw_lock_suspend(void); +void rtw_unlock_suspend(void); + +/* File operation APIs, just for linux now */ +int rtw_is_file_readable(char *path); +int rtw_retrive_from_file(char *path, u8* buf, u32 sz); +int rtw_store_to_file(char *path, u8* buf, u32 sz); + +#define NDEV_FMT "%s" +#define NDEV_ARG(ndev) ndev->name +#define ADPT_FMT "%s" +#define ADPT_ARG(adapter) adapter->pnetdev->name +#define FUNC_NDEV_FMT "%s(%s)" +#define FUNC_NDEV_ARG(ndev) __func__, ndev->name +#define FUNC_ADPT_FMT "%s(%s)" +#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name + +#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1) + +u64 rtw_modular6423a(u64 x, u64 y); +u64 rtw_division6423a(u64 x, u64 y); + + +/* Macros for handling unaligned memory accesses */ + +#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define RTW_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define RTW_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define RTW_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define RTW_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define RTW_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define RTW_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + +struct rtw_cbuf { + u32 write; + u32 read; + u32 size; + void *bufs[0]; +}; + +bool rtw_cbuf_full23a(struct rtw_cbuf *cbuf); +bool rtw_cbuf_empty23a(struct rtw_cbuf *cbuf); +bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf); +void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf); +struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size); +void rtw_cbuf_free(struct rtw_cbuf *cbuf); +int rtw_change_ifname(struct rtw_adapter *padapter, const char *ifname); +s32 c2h_evt_hdl(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter); +void indicate_wx_scan_complete_event(struct rtw_adapter *padapter); +u8 rtw_do_join23a(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/recv_osdep.h b/drivers/staging/rtl8723au/include/recv_osdep.h new file mode 100644 index 000000000000..15c94b6168bf --- /dev/null +++ b/drivers/staging/rtl8723au/include/recv_osdep.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RECV_OSDEP_H_ +#define __RECV_OSDEP_H_ + +#include +#include + +int _rtw_init_recv_priv23a(struct recv_priv *precvpriv, struct rtw_adapter *padapter); +void _rtw_free_recv_priv23a (struct recv_priv *precvpriv); + +int rtw_recv_entry23a(struct recv_frame *precv_frame); +int rtw_recv_indicatepkt23a(struct rtw_adapter *adapter, struct recv_frame *precv_frame); +void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt); + +void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame); +void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup); + +int rtw_init_recv_priv(struct recv_priv *precvpriv, struct rtw_adapter *padapter); +void rtw_free_recv_priv (struct recv_priv *precvpriv); + +int rtw_os_recv_resource_init(struct recv_priv *precvpriv, struct rtw_adapter *padapter); +int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, struct recv_frame *precvframe); +void rtw_os_recv_resource_free(struct recv_priv *precvpriv); + +int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); +int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); + +void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf); + +void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h new file mode 100644 index 000000000000..5777eda01403 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h @@ -0,0 +1,1672 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_BT_COEXIST_H__ +#define __RTL8723A_BT_COEXIST_H__ + +#include +#include "odm_precomp.h" + + +#define __BT_C__ 1 +#define __BT_HANDLEPACKET_C__ 1 +#define __BT_HCI_C__ 1 +#define __HALBTC87231ANT_C__ 1 +#define __HALBTC87232ANT_C__ 1 +#define __HALBTC8723_C__ 1 +#define __HALBTCCSR1ANT_C__ 1 +#define __HALBTCCSR2ANT_C__ 1 +#define __HALBTCOEXIST_C__ 1 +#define __HALBT_C__ 1 + +#ifdef __BT_C__ /* COMMON/BT.h */ + +/* HEADER/PlatformDef.h */ +enum rt_media_status { + RT_MEDIA_DISCONNECT = 0, + RT_MEDIA_CONNECT = 1 +}; + +/* ===== Below this line is sync from SD7 driver COMMON/BT.h ===== */ + +#define BT_TMP_BUF_SIZE 100 + +void BT_SignalCompensation(struct rtw_adapter *padapter, + u8 *rssi_wifi, u8 *rssi_bt); +void BT_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType); +void BT_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action); +void BT_WifiMediaStatusNotify(struct rtw_adapter *padapter, + enum rt_media_status mstatus); +void BT_SpecialPacketNotify(struct rtw_adapter * padapter); +void BT_HaltProcess(struct rtw_adapter * padapter); +void BT_LpsLeave(struct rtw_adapter * padapter); + + +#define BT_HsConnectionEstablished(Adapter) false +/* ===== End of sync from SD7 driver COMMON/BT.h ===== */ +#endif /* __BT_C__ */ + +#ifdef __BT_HCI_C__ /* COMMON/bt_hci.h */ + +/* HEADER/SecurityType.h */ +#define TKIP_ENC_KEY_POS 32 /* KEK_LEN+KEK_LEN) */ +#define MAXRSNIELEN 256 + +/* COMMON/Protocol802_11.h */ +/* */ +/* 802.11 Management frame Status Code field */ +/* */ +struct octet_string { + u8 *Octet; + u16 Length; +}; + + +/* AES_CCMP specific */ +enum { + AESCCMP_BLK_SIZE = 16, /* # octets in an AES block */ + AESCCMP_MAX_PACKET = 4*512, /* largest packet size */ + AESCCMP_N_RESERVED = 0, /* reserved nonce octet value */ + AESCCMP_A_DATA = 0x40, /* the Adata bit in the flags */ + AESCCMP_M_SHIFT = 3, /* how much to shift the 3-bit M field */ + AESCCMP_L_SHIFT = 0, /* how much to shift the 3-bit L field */ + AESCCMP_L_SIZE = 2, /* size of the l(m) length field (in octets) */ + AESCCMP_OFFSET_SC = 22, + AESCCMP_OFFSET_DURATION = 4, + AESCCMP_OFFSET_A2 = 10, + AESCCMP_OFFSET_A4 = 24, + AESCCMP_QC_TID_MASK = 0x0f, + AESCCMP_BLK_SIZE_TOTAL = 16*16, /* Added by Annie for CKIP AES MIC BSOD, 2006-08-17. */ + /* 16*8 < 4*60 Resove to 16*16 */ +}; + +/* Key Length */ +#define PMK_LEN 32 +#define PTK_LEN_TKIP 64 +#define GTK_LEN 32 +#define KEY_NONCE_LEN 32 + + +/* COMMON/Dot11d.h */ +struct chnl_txpower_triple { + u8 FirstChnl; + u8 NumChnls; + s8 MaxTxPowerInDbm; +}; + + +/* ===== Below this line is sync from SD7 driver COMMON/bt_hci.h ===== */ +/* The following is for BT 3.0 + HS HCI COMMAND ERRORS CODES */ + +#define Max80211PALPDUSize 1492 +#define Max80211AMPASSOCLen 672 +#define MinGUserPrio 4 +#define MaxGUserPrio 7 +#define BEUserPrio0 0 +#define BEUserPrio1 3 +#define Max80211BeaconPeriod 2000 +#define ShortRangeModePowerMax 4 + +#define BT_Default_Chnl 10 +#define ACLDataHeaderLen 4 + +#define BTTotalDataBlockNum 0x100 +#define BTLocalBufNum 0x200 +#define BTMaxDataBlockLen 0x800 +#define BTTOTALBANDWIDTH 0x7530 +#define BTMAXBANDGUBANDWIDTH 0x4e20 +#define TmpLocalBufSize 0x100 +#define BTSynDataPacketLength 0xff +/* */ + +#define BTMaxAuthCount 5 +#define BTMaxAsocCount 5 + +#define MAX_LOGICAL_LINK_NUM 2 /* temporarily define */ +#define MAX_BT_ASOC_ENTRY_NUM 2 /* temporarily define */ + +#define INVALID_PL_HANDLE 0xff +#define INVALID_ENTRY_NUM 0xff +/* */ + +#define CAM_BT_START_INDEX (HALF_CAM_ENTRY - 4) /* MAX_BT_ASOC_ENTRY_NUM : 4 !!! */ +#define BT_HWCAM_STAR CAM_BT_START_INDEX /* We used HALF_CAM_ENTRY ~ HALF_CAM_ENTRY -MAX_BT_ASOC_ENTRY_NUM */ + +enum hci_status { + HCI_STATUS_SUCCESS = 0x00, /* Success */ + HCI_STATUS_UNKNOW_HCI_CMD = 0x01, /* Unknown HCI Command */ + HCI_STATUS_UNKNOW_CONNECT_ID = 0X02, /* Unknown Connection Identifier */ + HCI_STATUS_HW_FAIL = 0X03, /* Hardware Failure */ + HCI_STATUS_PAGE_TIMEOUT = 0X04, /* Page Timeout */ + HCI_STATUS_AUTH_FAIL = 0X05, /* Authentication Failure */ + HCI_STATUS_PIN_OR_KEY_MISSING = 0X06, /* PIN or Key Missing */ + HCI_STATUS_MEM_CAP_EXCEED = 0X07, /* Memory Capacity Exceeded */ + HCI_STATUS_CONNECT_TIMEOUT = 0X08, /* Connection Timeout */ + HCI_STATUS_CONNECT_LIMIT = 0X09, /* Connection Limit Exceeded */ + HCI_STATUS_SYN_CONNECT_LIMIT = 0X0a, /* Synchronous Connection Limit To A Device Exceeded */ + HCI_STATUS_ACL_CONNECT_EXISTS = 0X0b, /* ACL Connection Already Exists */ + HCI_STATUS_CMD_DISALLOW = 0X0c, /* Command Disallowed */ + HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE = 0X0d, /* Connection Rejected due to Limited Resources */ + HCI_STATUS_CONNECT_RJT_SEC_REASON = 0X0e, /* Connection Rejected Due To Security Reasons */ + HCI_STATUS_CONNECT_RJT_UNACCEPT_BD_ADDR = 0X0f, /* Connection Rejected due to Unacceptable BD_ADDR */ + HCI_STATUS_CONNECT_ACCEPT_TIMEOUT = 0X10, /* Connection Accept Timeout Exceeded */ + HCI_STATUS_UNSUPPORT_FEATURE_PARA_VALUE = 0X11, /* Unsupported Feature or Parameter Value */ + HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE = 0X12, /* Invalid HCI Command Parameters */ + HCI_STATUS_REMOTE_USER_TERMINATE_CONNECT = 0X13, /* Remote User Terminated Connection */ + HCI_STATUS_REMOTE_DEV_TERMINATE_LOW_RESOURCE = 0X14, /* Remote Device Terminated Connection due to Low Resources */ + HCI_STATUS_REMOTE_DEV_TERMINATE_CONNECT_POWER_OFF = 0X15, /* Remote Device Terminated Connection due to Power Off */ + HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST = 0X16, /* Connection Terminated By Local Host */ + HCI_STATUS_REPEATE_ATTEMPT = 0X17, /* Repeated Attempts */ + HCI_STATUS_PAIR_NOT_ALLOW = 0X18, /* Pairing Not Allowed */ + HCI_STATUS_UNKNOW_LMP_PDU = 0X19, /* Unknown LMP PDU */ + HCI_STATUS_UNSUPPORT_REMOTE_LMP_FEATURE = 0X1a, /* Unsupported Remote Feature / Unsupported LMP Feature */ + HCI_STATUS_SOC_OFFSET_REJECT = 0X1b, /* SCO Offset Rejected */ + HCI_STATUS_SOC_INTERVAL_REJECT = 0X1c, /* SCO Interval Rejected */ + HCI_STATUS_SOC_AIR_MODE_REJECT = 0X1d,/* SCO Air Mode Rejected */ + HCI_STATUS_INVALID_LMP_PARA = 0X1e, /* Invalid LMP Parameters */ + HCI_STATUS_UNSPECIFIC_ERROR = 0X1f, /* Unspecified Error */ + HCI_STATUS_UNSUPPORT_LMP_PARA_VALUE = 0X20, /* Unsupported LMP Parameter Value */ + HCI_STATUS_ROLE_CHANGE_NOT_ALLOW = 0X21, /* Role Change Not Allowed */ + HCI_STATUS_LMP_RESPONSE_TIMEOUT = 0X22, /* LMP Response Timeout */ + HCI_STATUS_LMP_ERROR_TRANSACTION_COLLISION = 0X23, /* LMP Error Transaction Collision */ + HCI_STATUS_LMP_PDU_NOT_ALLOW = 0X24, /* LMP PDU Not Allowed */ + HCI_STATUS_ENCRYPTION_MODE_NOT_ALLOW = 0X25, /* Encryption Mode Not Acceptable */ + HCI_STATUS_LINK_KEY_CAN_NOT_CHANGE = 0X26, /* Link Key Can Not be Changed */ + HCI_STATUS_REQUEST_QOS_NOT_SUPPORT = 0X27, /* Requested QoS Not Supported */ + HCI_STATUS_INSTANT_PASSED = 0X28, /* Instant Passed */ + HCI_STATUS_PAIRING_UNIT_KEY_NOT_SUPPORT = 0X29, /* Pairing With Unit Key Not Supported */ + HCI_STATUS_DIFFERENT_TRANSACTION_COLLISION = 0X2a, /* Different Transaction Collision */ + HCI_STATUS_RESERVE_1 = 0X2b, /* Reserved */ + HCI_STATUS_QOS_UNACCEPT_PARA = 0X2c, /* QoS Unacceptable Parameter */ + HCI_STATUS_QOS_REJECT = 0X2d, /* QoS Rejected */ + HCI_STATUS_CHNL_CLASSIFICATION_NOT_SUPPORT = 0X2e, /* Channel Classification Not Supported */ + HCI_STATUS_INSUFFICIENT_SECURITY = 0X2f, /* Insufficient Security */ + HCI_STATUS_PARA_OUT_OF_RANGE = 0x30, /* Parameter Out Of Mandatory Range */ + HCI_STATUS_RESERVE_2 = 0X31, /* Reserved */ + HCI_STATUS_ROLE_SWITCH_PENDING = 0X32, /* Role Switch Pending */ + HCI_STATUS_RESERVE_3 = 0X33, /* Reserved */ + HCI_STATUS_RESERVE_SOLT_VIOLATION = 0X34, /* Reserved Slot Violation */ + HCI_STATUS_ROLE_SWITCH_FAIL = 0X35, /* Role Switch Failed */ + HCI_STATUS_EXTEND_INQUIRY_RSP_TOO_LARGE = 0X36, /* Extended Inquiry Response Too Large */ + HCI_STATUS_SEC_SIMPLE_PAIRING_NOT_SUPPORT = 0X37, /* Secure Simple Pairing Not Supported By Host. */ + HCI_STATUS_HOST_BUSY_PAIRING = 0X38, /* Host Busy - Pairing */ + HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND = 0X39, /* Connection Rejected due to No Suitable Channel Found */ + HCI_STATUS_CONTROLLER_BUSY = 0X3a /* CONTROLLER BUSY */ +}; + +/* */ +/* The following is for BT 3.0 + HS HCI COMMAND */ +/* */ + +/* bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ +/* | OCF | OGF | */ +/* */ + +/* OGF 0x01 */ +#define LINK_CONTROL_COMMANDS 0x01 +enum link_control_commands { + HCI_INQUIRY = 0x0001, + HCI_INQUIRY_CANCEL = 0x0002, + HCI_PERIODIC_INQUIRY_MODE = 0x0003, + HCI_EXIT_PERIODIC_INQUIRY_MODE = 0x0004, + HCI_CREATE_CONNECTION = 0x0005, + HCI_DISCONNECT = 0x0006, + HCI_CREATE_CONNECTION_CANCEL = 0x0008, + HCI_ACCEPT_CONNECTIONREQUEST = 0x0009, + HCI_REJECT_CONNECTION_REQUEST = 0x000a, + HCI_LINK_KEY_REQUEST_REPLY = 0x000b, + HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY = 0x000c, + HCI_PIN_CODE_REQUEST_REPLY = 0x000d, + HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY = 0x000e, + HCI_CHANGE_CONNECTION_PACKET_TYPE = 0x000f, + HCI_AUTHENTICATION_REQUESTED = 0x0011, + HCI_SET_CONNECTION_ENCRYPTION = 0x0013, + HCI_CHANGE_CONNECTION_LINK_KEY = 0x0015, + HCI_MASTER_LINK_KEY = 0x0017, + HCI_REMOTE_NAME_REQUEST = 0x0019, + HCI_REMOTE_NAME_REQUEST_CANCEL = 0x001a, + HCI_READ_REMOTE_SUPPORTED_FEATURES = 0x001b, + HCI_READ_REMOTE_EXTENDED_FEATURES = 0x001c, + HCI_READ_REMOTE_VERSION_INFORMATION = 0x001d, + HCI_READ_CLOCK_OFFSET = 0x001f, + HCI_READ_LMP_HANDLE = 0x0020, + HCI_SETUP_SYNCHRONOUS_CONNECTION = 0x0028, + HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST = 0x0029, + HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST = 0x002a, + HCI_IO_CAPABILITY_REQUEST_REPLY = 0x002b, + HCI_USER_CONFIRMATION_REQUEST_REPLY = 0x002c, + HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = 0x002d, + HCI_USER_PASSKEY_REQUEST_REPLY = 0x002e, + HCI_USER_PASSKEY_REQUESTNEGATIVE_REPLY = 0x002f, + HCI_REMOTE_OOB_DATA_REQUEST_REPLY = 0x0030, + HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = 0x0033, + HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 0x0034, + HCI_CREATE_PHYSICAL_LINK = 0x0035, + HCI_ACCEPT_PHYSICAL_LINK = 0x0036, + HCI_DISCONNECT_PHYSICAL_LINK = 0x0037, + HCI_CREATE_LOGICAL_LINK = 0x0038, + HCI_ACCEPT_LOGICAL_LINK = 0x0039, + HCI_DISCONNECT_LOGICAL_LINK = 0x003a, + HCI_LOGICAL_LINK_CANCEL = 0x003b, + HCI_FLOW_SPEC_MODIFY = 0x003c +}; + +/* OGF 0x02 */ +#define HOLD_MODE_COMMAND 0x02 +enum hold_mode_command { + HCI_HOLD_MODE = 0x0001, + HCI_SNIFF_MODE = 0x0002, + HCI_EXIT_SNIFF_MODE = 0x0003, + HCI_PARK_STATE = 0x0005, + HCI_EXIT_PARK_STATE = 0x0006, + HCI_QOS_SETUP = 0x0007, + HCI_ROLE_DISCOVERY = 0x0009, + HCI_SWITCH_ROLE = 0x000b, + HCI_READ_LINK_POLICY_SETTINGS = 0x000c, + HCI_WRITE_LINK_POLICY_SETTINGS = 0x000d, + HCI_READ_DEFAULT_LINK_POLICY_SETTINGS = 0x000e, + HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS = 0x000f, + HCI_FLOW_SPECIFICATION = 0x0010, + HCI_SNIFF_SUBRATING = 0x0011 +}; + +/* OGF 0x03 */ +#define OGF_SET_EVENT_MASK_COMMAND 0x03 +enum set_event_mask_command { + HCI_SET_EVENT_MASK = 0x0001, + HCI_RESET = 0x0003, + HCI_SET_EVENT_FILTER = 0x0005, + HCI_FLUSH = 0x0008, + HCI_READ_PIN_TYPE = 0x0009, + HCI_WRITE_PIN_TYPE = 0x000a, + HCI_CREATE_NEW_UNIT_KEY = 0x000b, + HCI_READ_STORED_LINK_KEY = 0x000d, + HCI_WRITE_STORED_LINK_KEY = 0x0011, + HCI_DELETE_STORED_LINK_KEY = 0x0012, + HCI_WRITE_LOCAL_NAME = 0x0013, + HCI_READ_LOCAL_NAME = 0x0014, + HCI_READ_CONNECTION_ACCEPT_TIMEOUT = 0x0015, + HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT = 0x0016, + HCI_READ_PAGE_TIMEOUT = 0x0017, + HCI_WRITE_PAGE_TIMEOUT = 0x0018, + HCI_READ_SCAN_ENABLE = 0x0019, + HCI_WRITE_SCAN_ENABLE = 0x001a, + HCI_READ_PAGE_SCAN_ACTIVITY = 0x001b, + HCI_WRITE_PAGE_SCAN_ACTIVITY = 0x001c, + HCI_READ_INQUIRY_SCAN_ACTIVITY = 0x001d, + HCI_WRITE_INQUIRY_SCAN_ACTIVITY = 0x001e, + HCI_READ_AUTHENTICATION_ENABLE = 0x001f, + HCI_WRITE_AUTHENTICATION_ENABLE = 0x0020, + HCI_READ_CLASS_OF_DEVICE = 0x0023, + HCI_WRITE_CLASS_OF_DEVICE = 0x0024, + HCI_READ_VOICE_SETTING = 0x0025, + HCI_WRITE_VOICE_SETTING = 0x0026, + HCI_READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0027, + HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0028, + HCI_READ_NUM_BROADCAST_RETRANSMISSIONS = 0x0029, + HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS = 0x002a, + HCI_READ_HOLD_MODE_ACTIVITY = 0x002b, + HCI_WRITE_HOLD_MODE_ACTIVITY = 0x002c, + HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x002e, + HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x002f, + HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL = 0x0031, + HCI_HOST_BUFFER_SIZE = 0x0033, + HCI_HOST_NUMBER_OF_COMPLETED_PACKETS = 0x0035, + HCI_READ_LINK_SUPERVISION_TIMEOUT = 0x0036, + HCI_WRITE_LINK_SUPERVISION_TIMEOUT = 0x0037, + HCI_READ_NUMBER_OF_SUPPORTED_IAC = 0x0038, + HCI_READ_CURRENT_IAC_LAP = 0x0039, + HCI_WRITE_CURRENT_IAC_LAP = 0x003a, + HCI_READ_PAGE_SCAN_MODE = 0x003d, + HCI_WRITE_PAGE_SCAN_MODE = 0x003e, + HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION = 0x003f, + HCI_READ_INQUIRY_SCAN_TYPE = 0x0042, + HCI_WRITE_INQUIRY_SCAN_TYPE = 0x0043, + HCI_READ_INQUIRY_MODE = 0x0044, + HCI_WRITE_INQUIRY_MODE = 0x0045, + HCI_READ_PAGE_SCAN_TYPE = 0x0046, + HCI_WRITE_PAGE_SCAN_TYPE = 0x0047, + HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE = 0x0048, + HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE = 0x0049, + HCI_READ_EXTENDED_INQUIRY_RESPONSE = 0x0051, + HCI_WRITE_EXTENDED_INQUIRY_RESPONSE = 0x0052, + HCI_REFRESH_ENCRYPTION_KEY = 0x0053, + HCI_READ_SIMPLE_PAIRING_MODE = 0x0055, + HCI_WRITE_SIMPLE_PAIRING_MODE = 0x0056, + HCI_READ_LOCAL_OOB_DATA = 0x0057, + HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = 0x0058, + HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = 0x0059, + HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING = 0x005a, + HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING = 0x005b, + HCI_ENHANCED_FLUSH = 0x005f, + HCI_SEND_KEYPRESS_NOTIFICATION = 0x0060, + HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0061, + HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0062, + HCI_SET_EVENT_MASK_PAGE_2 = 0x0063, + HCI_READ_LOCATION_DATA = 0x0064, + HCI_WRITE_LOCATION_DATA = 0x0065, + HCI_READ_FLOW_CONTROL_MODE = 0x0066, + HCI_WRITE_FLOW_CONTROL_MODE = 0x0067, + HCI_READ_ENHANCE_TRANSMIT_POWER_LEVEL = 0x0068, + HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT = 0x0069, + HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT = 0x006a, + HCI_SHORT_RANGE_MODE = 0x006b +}; + +/* OGF 0x04 */ +#define OGF_INFORMATIONAL_PARAMETERS 0x04 +enum informational_params { + HCI_READ_LOCAL_VERSION_INFORMATION = 0x0001, + HCI_READ_LOCAL_SUPPORTED_COMMANDS = 0x0002, + HCI_READ_LOCAL_SUPPORTED_FEATURES = 0x0003, + HCI_READ_LOCAL_EXTENDED_FEATURES = 0x0004, + HCI_READ_BUFFER_SIZE = 0x0005, + HCI_READ_BD_ADDR = 0x0009, + HCI_READ_DATA_BLOCK_SIZE = 0x000a +}; + +/* OGF 0x05 */ +#define OGF_STATUS_PARAMETERS 0x05 +enum status_params { + HCI_READ_FAILED_CONTACT_COUNTER = 0x0001, + HCI_RESET_FAILED_CONTACT_COUNTER = 0x0002, + HCI_READ_LINK_QUALITY = 0x0003, + HCI_READ_RSSI = 0x0005, + HCI_READ_AFH_CHANNEL_MAP = 0x0006, + HCI_READ_CLOCK = 0x0007, + HCI_READ_ENCRYPTION_KEY_SIZE = 0x0008, + HCI_READ_LOCAL_AMP_INFO = 0x0009, + HCI_READ_LOCAL_AMP_ASSOC = 0x000a, + HCI_WRITE_REMOTE_AMP_ASSOC = 0x000b +}; + +/* OGF 0x06 */ +#define OGF_TESTING_COMMANDS 0x06 +enum testing_commands { + HCI_READ_LOOPBACK_MODE = 0x0001, + HCI_WRITE_LOOPBACK_MODE = 0x0002, + HCI_ENABLE_DEVICE_UNDER_TEST_MODE = 0x0003, + HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE = 0x0004, + HCI_ENABLE_AMP_RECEIVER_REPORTS = 0x0007, + HCI_AMP_TEST_END = 0x0008, + HCI_AMP_TEST_COMMAND = 0x0009 +}; + +/* OGF 0x3f */ +#define OGF_EXTENSION 0X3f +enum hci_extension_commands { + HCI_SET_ACL_LINK_DATA_FLOW_MODE = 0x0010, + HCI_SET_ACL_LINK_STATUS = 0x0020, + HCI_SET_SCO_LINK_STATUS = 0x0030, + HCI_SET_RSSI_VALUE = 0x0040, + HCI_SET_CURRENT_BLUETOOTH_STATUS = 0x0041, + + /* The following is for RTK8723 */ + HCI_EXTENSION_VERSION_NOTIFY = 0x0100, + HCI_LINK_STATUS_NOTIFY = 0x0101, + HCI_BT_OPERATION_NOTIFY = 0x0102, + HCI_ENABLE_WIFI_SCAN_NOTIFY = 0x0103, + + + /* The following is for IVT */ + HCI_WIFI_CURRENT_CHANNEL = 0x0300, + HCI_WIFI_CURRENT_BANDWIDTH = 0x0301, + HCI_WIFI_CONNECTION_STATUS = 0x0302, +}; + +enum bt_spec { + BT_SPEC_1_0_b = 0x00, + BT_SPEC_1_1 = 0x01, + BT_SPEC_1_2 = 0x02, + BT_SPEC_2_0_EDR = 0x03, + BT_SPEC_2_1_EDR = 0x04, + BT_SPEC_3_0_HS = 0x05, + BT_SPEC_4_0 = 0x06 +}; + +/* The following is for BT 3.0 + HS EVENTS */ +enum hci_event { + HCI_EVENT_INQUIRY_COMPLETE = 0x01, + HCI_EVENT_INQUIRY_RESULT = 0x02, + HCI_EVENT_CONNECTION_COMPLETE = 0x03, + HCI_EVENT_CONNECTION_REQUEST = 0x04, + HCI_EVENT_DISCONNECTION_COMPLETE = 0x05, + HCI_EVENT_AUTHENTICATION_COMPLETE = 0x06, + HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE = 0x07, + HCI_EVENT_ENCRYPTION_CHANGE = 0x08, + HCI_EVENT_CHANGE_LINK_KEY_COMPLETE = 0x09, + HCI_EVENT_MASTER_LINK_KEY_COMPLETE = 0x0a, + HCI_EVENT_READ_REMOTE_SUPPORT_FEATURES_COMPLETE = 0x0b, + HCI_EVENT_READ_REMOTE_VER_INFO_COMPLETE = 0x0c, + HCI_EVENT_QOS_SETUP_COMPLETE = 0x0d, + HCI_EVENT_COMMAND_COMPLETE = 0x0e, + HCI_EVENT_COMMAND_STATUS = 0x0f, + HCI_EVENT_HARDWARE_ERROR = 0x10, + HCI_EVENT_FLUSH_OCCRUED = 0x11, + HCI_EVENT_ROLE_CHANGE = 0x12, + HCI_EVENT_NUMBER_OF_COMPLETE_PACKETS = 0x13, + HCI_EVENT_MODE_CHANGE = 0x14, + HCI_EVENT_RETURN_LINK_KEYS = 0x15, + HCI_EVENT_PIN_CODE_REQUEST = 0x16, + HCI_EVENT_LINK_KEY_REQUEST = 0x17, + HCI_EVENT_LINK_KEY_NOTIFICATION = 0x18, + HCI_EVENT_LOOPBACK_COMMAND = 0x19, + HCI_EVENT_DATA_BUFFER_OVERFLOW = 0x1a, + HCI_EVENT_MAX_SLOTS_CHANGE = 0x1b, + HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE = 0x1c, + HCI_EVENT_CONNECT_PACKET_TYPE_CHANGE = 0x1d, + HCI_EVENT_QOS_VIOLATION = 0x1e, + HCI_EVENT_PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20, + HCI_EVENT_FLOW_SEPC_COMPLETE = 0x21, + HCI_EVENT_INQUIRY_RESULT_WITH_RSSI = 0x22, + HCI_EVENT_READ_REMOTE_EXT_FEATURES_COMPLETE = 0x23, + HCI_EVENT_SYNC_CONNECT_COMPLETE = 0x2c, + HCI_EVENT_SYNC_CONNECT_CHANGE = 0x2d, + HCI_EVENT_SNIFFER_SUBRATING = 0x2e, + HCI_EVENT_EXTENTED_INQUIRY_RESULT = 0x2f, + HCI_EVENT_ENCRYPTION_KEY_REFLASH_COMPLETE = 0x30, + HCI_EVENT_IO_CAPIBILITY_COMPLETE = 0x31, + HCI_EVENT_IO_CAPIBILITY_RESPONSE = 0x32, + HCI_EVENT_USER_CONFIRMTION_REQUEST = 0x33, + HCI_EVENT_USER_PASSKEY_REQUEST = 0x34, + HCI_EVENT_REMOTE_OOB_DATA_REQUEST = 0x35, + HCI_EVENT_SIMPLE_PAIRING_COMPLETE = 0x36, + HCI_EVENT_LINK_SUPERVISION_TIMEOUT_CHANGE = 0x38, + HCI_EVENT_ENHANCED_FLUSH_COMPLETE = 0x39, + HCI_EVENT_USER_PASSKEY_NOTIFICATION = 0x3b, + HCI_EVENT_KEYPRESS_NOTIFICATION = 0x3c, + HCI_EVENT_REMOTE_HOST_SUPPORT_FEATURES_NOTIFICATION = 0x3d, + HCI_EVENT_PHY_LINK_COMPLETE = 0x40, + HCI_EVENT_CHANNEL_SELECT = 0x41, + HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE = 0x42, + HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING = 0x43, + HCI_EVENT_PHY_LINK_RECOVER = 0x44, + HCI_EVENT_LOGICAL_LINK_COMPLETE = 0x45, + HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE = 0x46, + HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE = 0x47, + HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS = 0x48, + HCI_EVENT_AMP_START_TEST = 0x49, + HCI_EVENT_AMP_TEST_END = 0x4a, + HCI_EVENT_AMP_RECEIVER_REPORT = 0x4b, + HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE = 0x4c, + HCI_EVENT_AMP_STATUS_CHANGE = 0x4d, + HCI_EVENT_EXTENSION_RTK = 0xfe, + HCI_EVENT_EXTENSION_MOTO = 0xff, +}; + +enum hci_extension_event_moto { + HCI_EVENT_GET_BT_RSSI = 0x01, +}; + +enum hci_extension_event { + HCI_EVENT_EXT_WIFI_SCAN_NOTIFY = 0x01, +}; + +enum hci_event_mask_page_2 { + EMP2_HCI_EVENT_PHY_LINK_COMPLETE = 0x0000000000000001, + EMP2_HCI_EVENT_CHANNEL_SELECT = 0x0000000000000002, + EMP2_HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE = 0x0000000000000004, + EMP2_HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING = 0x0000000000000008, + EMP2_HCI_EVENT_PHY_LINK_RECOVER = 0x0000000000000010, + EMP2_HCI_EVENT_LOGICAL_LINK_COMPLETE = 0x0000000000000020, + EMP2_HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE = 0x0000000000000040, + EMP2_HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE = 0x0000000000000080, + EMP2_HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS = 0x0000000000000100, + EMP2_HCI_EVENT_AMP_START_TEST = 0x0000000000000200, + EMP2_HCI_EVENT_AMP_TEST_END = 0x0000000000000400, + EMP2_HCI_EVENT_AMP_RECEIVER_REPORT = 0x0000000000000800, + EMP2_HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE = 0x0000000000001000, + EMP2_HCI_EVENT_AMP_STATUS_CHANGE = 0x0000000000002000, +}; + +enum hci_state_machine { + HCI_STATE_STARTING = 0x01, + HCI_STATE_CONNECTING = 0x02, + HCI_STATE_AUTHENTICATING = 0x04, + HCI_STATE_CONNECTED = 0x08, + HCI_STATE_DISCONNECTING = 0x10, + HCI_STATE_DISCONNECTED = 0x20 +}; + +enum amp_assoc_structure_type { + AMP_MAC_ADDR = 0x01, + AMP_PREFERRED_CHANNEL_LIST = 0x02, + AMP_CONNECTED_CHANNEL = 0x03, + AMP_80211_PAL_CAP_LIST = 0x04, + AMP_80211_PAL_VISION = 0x05, + AMP_RESERVED_FOR_TESTING = 0x33 +}; + +enum amp_btap_type { + AMP_BTAP_NONE, + AMP_BTAP_CREATOR, + AMP_BTAP_JOINER +}; + +enum hci_state_with_cmd { + STATE_CMD_CREATE_PHY_LINK, + STATE_CMD_ACCEPT_PHY_LINK, + STATE_CMD_DISCONNECT_PHY_LINK, + STATE_CMD_CONNECT_ACCEPT_TIMEOUT, + STATE_CMD_MAC_START_COMPLETE, + STATE_CMD_MAC_START_FAILED, + STATE_CMD_MAC_CONNECT_COMPLETE, + STATE_CMD_MAC_CONNECT_FAILED, + STATE_CMD_MAC_DISCONNECT_INDICATE, + STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, + STATE_CMD_4WAY_FAILED, + STATE_CMD_4WAY_SUCCESSED, + STATE_CMD_ENTER_STATE, + STATE_CMD_NO_SUCH_CMD, +}; + +enum hci_service_type { + SERVICE_NO_TRAFFIC, + SERVICE_BEST_EFFORT, + SERVICE_GUARANTEE +}; + +enum hci_traffic_mode { + TRAFFIC_MODE_BEST_EFFORT = 0x00, + TRAFFIC_MODE_GUARANTEED_LATENCY = 0x01, + TRAFFIC_MODE_GUARANTEED_BANDWIDTH = 0x02, + TRAFFIC_MODE_GUARANTEED_LATENCY_AND_BANDWIDTH = 0x03 +}; + +#define HCIOPCODE(_OCF, _OGF) (_OGF<<10|_OCF) +#define HCIOPCODELOW(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)&0x00ff) +#define HCIOPCODEHIGHT(_OCF, _OGF) (u8)(HCIOPCODE(_OCF, _OGF)>>8) + +#define TWOBYTE_HIGHTBYTE(_DATA) (u8)(_DATA>>8) +#define TWOBYTE_LOWBYTE(_DATA) (u8)(_DATA) + +enum amp_status { + AMP_STATUS_AVA_PHY_PWR_DWN = 0x0, + AMP_STATUS_BT_USE_ONLY = 0x1, + AMP_STATUS_NO_CAPACITY_FOR_BT = 0x2, + AMP_STATUS_LOW_CAPACITY_FOR_BT = 0x3, + AMP_STATUS_MEDIUM_CAPACITY_FOR_BT = 0x4, + AMP_STATUS_HIGH_CAPACITY_FOR_BT = 0x5, + AMP_STATUS_FULL_CAPACITY_FOR_BT = 0x6 +}; + +enum bt_wpa_msg_type { + Type_BT_4way1st = 0, + Type_BT_4way2nd = 1, + Type_BT_4way3rd = 2, + Type_BT_4way4th = 3, + Type_BT_unknow = 4 +}; + +enum bt_connect_type { + BT_CONNECT_AUTH_REQ = 0x00, + BT_CONNECT_AUTH_RSP = 0x01, + BT_CONNECT_ASOC_REQ = 0x02, + BT_CONNECT_ASOC_RSP = 0x03, + BT_DISCONNECT = 0x04 +}; + +enum bt_ll_service_type { + BT_LL_BE = 0x01, + BT_LL_GU = 0x02 +}; + +enum bt_ll_flowspec { + BT_TX_BE_FS, /* TX best effort flowspec */ + BT_RX_BE_FS, /* RX best effort flowspec */ + BT_TX_GU_FS, /* TX guaranteed latency flowspec */ + BT_RX_GU_FS, /* RX guaranteed latency flowspec */ + BT_TX_BE_AGG_FS, /* TX aggregated best effort flowspec */ + BT_RX_BE_AGG_FS, /* RX aggregated best effort flowspec */ + BT_TX_GU_BW_FS, /* TX guaranteed bandwidth flowspec */ + BT_RX_GU_BW_FS, /* RX guaranteed bandwidth flowspec */ + BT_TX_GU_LARGE_FS, /* TX guaranteed latency flowspec, for testing only */ + BT_RX_GU_LARGE_FS, /* RX guaranteed latency flowspec, for testing only */ +}; + +enum bt_traffic_mode { + BT_MOTOR_EXT_BE = 0x00, /* Best Effort. Default. for HCRP, PAN, SDP, RFCOMM-based profiles like FTP, OPP, SPP, DUN, etc. */ + BT_MOTOR_EXT_GUL = 0x01, /* Guaranteed Latency. This type of traffic is used e.g. for HID and AVRCP. */ + BT_MOTOR_EXT_GUB = 0X02, /* Guaranteed Bandwidth. */ + BT_MOTOR_EXT_GULB = 0X03 /* Guaranteed Latency and Bandwidth. for A2DP and VDP. */ +}; + +enum bt_traffic_mode_profile { + BT_PROFILE_NONE, + BT_PROFILE_A2DP, + BT_PROFILE_PAN, + BT_PROFILE_HID, + BT_PROFILE_SCO +}; + +enum bt_link_role { + BT_LINK_MASTER = 0, + BT_LINK_SLAVE = 1 +}; + +enum bt_state_wpa_auth { + STATE_WPA_AUTH_UNINITIALIZED, + STATE_WPA_AUTH_WAIT_PACKET_1, /* Join */ + STATE_WPA_AUTH_WAIT_PACKET_2, /* Creat */ + STATE_WPA_AUTH_WAIT_PACKET_3, + STATE_WPA_AUTH_WAIT_PACKET_4, + STATE_WPA_AUTH_SUCCESSED +}; + +#define BT_WPA_AUTH_TIMEOUT_PERIOD 1000 +#define BTMaxWPAAuthReTransmitCoun 5 + +#define MAX_AMP_ASSOC_FRAG_LEN 248 +#define TOTAL_ALLOCIATE_ASSOC_LEN 1000 + +struct hci_flow_spec { + u8 Identifier; + u8 ServiceType; + u16 MaximumSDUSize; + u32 SDUInterArrivalTime; + u32 AccessLatency; + u32 FlushTimeout; +}; + +struct hci_log_link_cmd_data { + u8 BtPhyLinkhandle; + u16 BtLogLinkhandle; + u8 BtTxFlowSpecID; + struct hci_flow_spec Tx_Flow_Spec; + struct hci_flow_spec Rx_Flow_Spec; + u32 TxPacketCount; + u32 BestEffortFlushTimeout; + + u8 bLLCompleteEventIsSet; + + u8 bLLCancelCMDIsSetandComplete; +}; + +struct hci_phy_link_cmd_data { + /* Physical_Link_Handle */ + u8 BtPhyLinkhandle; + + u16 LinkSuperversionTimeout; + + /* u16 SuperTimeOutCnt; */ + + /* Dedicated_AMP_Key_Length */ + u8 BtAMPKeyLen; + /* Dedicated_AMP_Key_Type */ + u8 BtAMPKeyType; + /* Dedicated_AMP_Key */ + u8 BtAMPKey[PMK_LEN]; +}; + +struct amp_assoc_structure { + /* TYPE ID */ + u8 TypeID; + /* Length */ + u16 Length; + /* Value */ + u8 Data[1]; +}; + +struct amp_pref_chnl_regulatory { + u8 reXId; + u8 regulatoryClass; + u8 coverageClass; +}; + +struct amp_assoc_cmd_data { + /* Physical_Link_Handle */ + u8 BtPhyLinkhandle; + /* Length_So_Far */ + u16 LenSoFar; + + u16 MaxRemoteASSOCLen; + /* AMP_ASSOC_Remaining_Length */ + u16 AMPAssocRemLen; + /* AMP_ASSOC_fragment */ + void *AMPAssocfragment; +}; + +struct hci_link_info { + u16 ConnectHandle; + u8 IncomingTrafficMode; + u8 OutgoingTrafficMode; + u8 BTProfile; + u8 BTCoreSpec; + s8 BT_RSSI; + u8 TrafficProfile; + u8 linkRole; +}; + +struct hci_ext_config { + struct hci_link_info linkInfo[MAX_BT_ASOC_ENTRY_NUM]; + u8 btOperationCode; + u16 CurrentConnectHandle; + u8 CurrentIncomingTrafficMode; + u8 CurrentOutgoingTrafficMode; + s8 MIN_BT_RSSI; + u8 NumberOfHandle; + u8 NumberOfSCO; + u8 CurrentBTStatus; + u16 HCIExtensionVer; + + /* Bt coexist related */ + u8 btProfileCase; + u8 btProfileAction; + u8 bManualControl; + u8 bBTBusy; + u8 bBTA2DPBusy; + u8 bEnableWifiScanNotify; + + u8 bHoldForBtOperation; + u32 bHoldPeriodCnt; +}; + +struct hci_acl_packet_data { + u16 ACLDataPacketLen; + u8 SyncDataPacketLen; + u16 TotalNumACLDataPackets; + u16 TotalSyncNumDataPackets; +}; + +struct hci_phy_link_bss_info { + u16 bdCap; /* capability information */ +}; + +struct packet_irp_hcicmd_data { + u16 OCF:10; + u16 OGF:6; + u8 Length; + u8 Data[20]; +}; + +struct bt_asoc_entry { + u8 bUsed; + u8 mAssoc; + u8 b4waySuccess; + u8 Bssid[6]; + struct hci_phy_link_cmd_data PhyLinkCmdData; + + struct hci_log_link_cmd_data LogLinkCmdData[MAX_LOGICAL_LINK_NUM]; + + struct hci_acl_packet_data ACLPacketsData; + + struct amp_assoc_cmd_data AmpAsocCmdData; + struct octet_string BTSsid; + u8 BTSsidBuf[33]; + + enum hci_status PhyLinkDisconnectReason; + + u8 bSendSupervisionPacket; + /* u8 CurrentSuervisionPacketSendNum; */ + /* u8 LastSuervisionPacketSendNum; */ + u32 NoRxPktCnt; + /* Is Creator or Joiner */ + enum amp_btap_type AMPRole; + + /* BT current state */ + u8 BtCurrentState; + /* BT next state */ + u8 BtNextState; + + u8 bNeedPhysLinkCompleteEvent; + + enum hci_status PhysLinkCompleteStatus; + + u8 BTRemoteMACAddr[6]; + + u32 BTCapability; + + u8 SyncDataPacketLen; + + u16 TotalSyncNumDataPackets; + u16 TotalNumACLDataPackets; + + u8 ShortRangeMode; + + u8 PTK[PTK_LEN_TKIP]; + u8 GTK[GTK_LEN]; + u8 ANonce[KEY_NONCE_LEN]; + u8 SNonce[KEY_NONCE_LEN]; + u64 KeyReplayCounter; + u8 WPAAuthReplayCount; + u8 AESKeyBuf[AESCCMP_BLK_SIZE_TOTAL]; + u8 PMK[PMK_LEN]; + enum bt_state_wpa_auth BTWPAAuthState; + s32 UndecoratedSmoothedPWDB; + + /* Add for HW security !! */ + u8 HwCAMIndex; /* Cam index */ + u8 bPeerQosSta; + + u32 rxSuvpPktCnt; +}; + +struct bt_traffic_statistics { + u8 bTxBusyTraffic; + u8 bRxBusyTraffic; + u8 bIdle; + u32 TxPktCntInPeriod; + u32 RxPktCntInPeriod; + u64 TxPktLenInPeriod; + u64 RxPktLenInPeriod; +}; + +struct bt_mgnt { + u8 bBTConnectInProgress; + u8 bLogLinkInProgress; + u8 bPhyLinkInProgress; + u8 bPhyLinkInProgressStartLL; + u8 BtCurrentPhyLinkhandle; + u16 BtCurrentLogLinkhandle; + u8 CurrentConnectEntryNum; + u8 DisconnectEntryNum; + u8 CurrentBTConnectionCnt; + enum bt_connect_type BTCurrentConnectType; + enum bt_connect_type BTReceiveConnectPkt; + u8 BTAuthCount; + u8 BTAsocCount; + u8 bStartSendSupervisionPkt; + u8 BtOperationOn; + u8 BTNeedAMPStatusChg; + u8 JoinerNeedSendAuth; + struct hci_phy_link_bss_info bssDesc; + struct hci_ext_config ExtConfig; + u8 bNeedNotifyAMPNoCap; + u8 bCreateSpportQos; + u8 bSupportProfile; + u8 BTChannel; + u8 CheckChnlIsSuit; + u8 bBtScan; + u8 btLogoTest; +}; + +struct bt_hci_dgb_info { + u32 hciCmdCnt; + u32 hciCmdCntUnknown; + u32 hciCmdCntCreatePhyLink; + u32 hciCmdCntAcceptPhyLink; + u32 hciCmdCntDisconnectPhyLink; + u32 hciCmdPhyLinkStatus; + u32 hciCmdCntCreateLogLink; + u32 hciCmdCntAcceptLogLink; + u32 hciCmdCntDisconnectLogLink; + u32 hciCmdCntReadLocalAmpAssoc; + u32 hciCmdCntWriteRemoteAmpAssoc; + u32 hciCmdCntSetAclLinkStatus; + u32 hciCmdCntSetScoLinkStatus; + u32 hciCmdCntExtensionVersionNotify; + u32 hciCmdCntLinkStatusNotify; +}; + +struct bt_irp_dgb_info { + u32 irpMJCreate; + /* Io Control */ + u32 irpIoControl; + u32 irpIoCtrlHciCmd; + u32 irpIoCtrlHciEvent; + u32 irpIoCtrlHciTxData; + u32 irpIoCtrlHciRxData; + u32 irpIoCtrlUnknown; + + u32 irpIoCtrlHciTxData1s; +}; + +struct bt_packet_dgb_info { + u32 btPktTxProbReq; + u32 btPktRxProbReq; + u32 btPktRxProbReqFail; + u32 btPktTxProbRsp; + u32 btPktRxProbRsp; + u32 btPktTxAuth; + u32 btPktRxAuth; + u32 btPktRxAuthButDrop; + u32 btPktTxAssocReq; + u32 btPktRxAssocReq; + u32 btPktRxAssocReqButDrop; + u32 btPktTxAssocRsp; + u32 btPktRxAssocRsp; + u32 btPktTxDisassoc; + u32 btPktRxDisassoc; + u32 btPktRxDeauth; + u32 btPktTx4way1st; + u32 btPktRx4way1st; + u32 btPktTx4way2nd; + u32 btPktRx4way2nd; + u32 btPktTx4way3rd; + u32 btPktRx4way3rd; + u32 btPktTx4way4th; + u32 btPktRx4way4th; + u32 btPktTxLinkSuperReq; + u32 btPktRxLinkSuperReq; + u32 btPktTxLinkSuperRsp; + u32 btPktRxLinkSuperRsp; + u32 btPktTxData; + u32 btPktRxData; +}; + +struct bt_dgb { + u8 dbgCtrl; + u32 dbgProfile; + struct bt_hci_dgb_info dbgHciInfo; + struct bt_irp_dgb_info dbgIrpInfo; + struct bt_packet_dgb_info dbgBtPkt; +}; + +struct bt_hci_info { + /* 802.11 Pal version specifier */ + u8 BTPalVersion; + u16 BTPalCompanyID; + u16 BTPalsubversion; + + /* Connected channel list */ + u16 BTConnectChnlListLen; + u8 BTConnectChnllist[64]; + + /* Fail contact counter */ + u16 FailContactCount; + + /* Event mask */ + u64 BTEventMask; + u64 BTEventMaskPage2; + + /* timeout var */ + u16 ConnAcceptTimeout; + u16 LogicalAcceptTimeout; + u16 PageTimeout; + + u8 LocationDomainAware; + u16 LocationDomain; + u8 LocationDomainOptions; + u8 LocationOptions; + + u8 FlowControlMode; + + /* Preferred channel list */ + u16 BtPreChnlListLen; + u8 BTPreChnllist[64]; + + u16 enFlush_LLH; /* enhanced flush handle */ + u16 FLTO_LLH; /* enhanced flush handle */ + + /* */ + /* Test command only. */ + u8 bInTestMode; + u8 bTestIsEnd; + u8 bTestNeedReport; + u8 TestScenario; + u8 TestReportInterval; + u8 TestCtrType; + u32 TestEventType; + u16 TestNumOfFrame; + u16 TestNumOfErrFrame; + u16 TestNumOfBits; + u16 TestNumOfErrBits; + /* */ +}; + +struct bt_traffic { + /* Add for check replay data */ + u8 LastRxUniFragNum; + u16 LastRxUniSeqNum; + + /* s32 EntryMaxUndecoratedSmoothedPWDB; */ + /* s32 EntryMinUndecoratedSmoothedPWDB; */ + + struct bt_traffic_statistics Bt30TrafficStatistics; +}; + +#define RT_WORK_ITEM struct work_struct + +struct bt_security { + /* WPA auth state + * May need to remove to BTSecInfo ... + * enum bt_state_wpa_auth BTWPAAuthState; + */ + struct octet_string RSNIE; + u8 RSNIEBuf[MAXRSNIELEN]; + u8 bRegNoEncrypt; + u8 bUsedHwEncrypt; +}; + +struct bt_30info { + struct rtw_adapter *padapter; + struct bt_asoc_entry BtAsocEntry[MAX_BT_ASOC_ENTRY_NUM]; + struct bt_mgnt BtMgnt; + struct bt_dgb BtDbg; + struct bt_hci_info BtHciInfo; + struct bt_traffic BtTraffic; + struct bt_security BtSec; + RT_WORK_ITEM HCICmdWorkItem; + struct timer_list BTHCICmdTimer; + RT_WORK_ITEM BTPsDisableWorkItem; + RT_WORK_ITEM BTConnectWorkItem; + struct timer_list BTHCIDiscardAclDataTimer; + struct timer_list BTHCIJoinTimeoutTimer; + struct timer_list BTTestSendPacketTimer; + struct timer_list BTDisconnectPhyLinkTimer; + struct timer_list BTBeaconTimer; + u8 BTBeaconTmrOn; + + struct timer_list BTPsDisableTimer; + + void * pBtChnlList; +}; + +struct packet_irp_acl_data { + u16 Handle:12; + u16 PB_Flag:2; + u16 BC_Flag:2; + u16 Length; + u8 Data[1]; +}; + +struct packet_irp_hcievent_data { + u8 EventCode; + u8 Length; + u8 Data[5]; +}; + +struct common_triple { + u8 byte_1st; + u8 byte_2nd; + u8 byte_3rd; +}; + +#define COUNTRY_STR_LEN 3 /* country string len = 3 */ + +#define LOCAL_PMK 0 + +enum hci_wifi_connect_status { + HCI_WIFI_NOT_CONNECTED = 0x0, + HCI_WIFI_CONNECTED = 0x1, + HCI_WIFI_CONNECT_IN_PROGRESS = 0x2, +}; + +enum hci_ext_bp_operation { + HCI_BT_OP_NONE = 0x0, + HCI_BT_OP_INQUIRY_START = 0x1, + HCI_BT_OP_INQUIRY_FINISH = 0x2, + HCI_BT_OP_PAGING_START = 0x3, + HCI_BT_OP_PAGING_SUCCESS = 0x4, + HCI_BT_OP_PAGING_UNSUCCESS = 0x5, + HCI_BT_OP_PAIRING_START = 0x6, + HCI_BT_OP_PAIRING_FINISH = 0x7, + HCI_BT_OP_BT_DEV_ENABLE = 0x8, + HCI_BT_OP_BT_DEV_DISABLE = 0x9, + HCI_BT_OP_MAX +}; + +/* Function proto type */ +struct btdata_entry { + struct list_head List; + void *pDataBlock; +}; + +#define BTHCI_SM_WITH_INFO(_Adapter, _StateToEnter, _StateCmd, _EntryNum) \ +{ \ + RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state change] caused by ""%s"", line =%d\n", __FUNCTION__, __LINE__)); \ + BTHCI_StateMachine(_Adapter, _StateToEnter, _StateCmd, _EntryNum);\ +} + +void BTHCI_EventParse(struct rtw_adapter * padapter, void *pEvntData, u32 dataLen); +#define BT_EventParse BTHCI_EventParse +u8 BTHCI_HsConnectionEstablished(struct rtw_adapter * padapter); +void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter * padapter); +void BTHCI_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType); +void BTHCI_StateMachine(struct rtw_adapter * padapter, u8 StateToEnter, enum hci_state_with_cmd StateCmd, u8 EntryNum); +void BTHCI_DisconnectPeer(struct rtw_adapter * padapter, u8 EntryNum); +void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter * padapter); +void BTHCI_EventAMPStatusChange(struct rtw_adapter * padapter, u8 AMP_Status); +void BTHCI_DisconnectAll(struct rtw_adapter * padapter); +enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter * padapter, struct packet_irp_hcicmd_data *pHciCmd); + +/* ===== End of sync from SD7 driver COMMON/bt_hci.h ===== */ +#endif /* __BT_HCI_C__ */ + +#ifdef __HALBTC87231ANT_C__ /* HAL/BTCoexist/HalBtc87231Ant.h */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */ +#define GET_BT_INFO(padapter) (&GET_HAL_DATA(padapter)->BtInfo) + +#define BTC_FOR_SCAN_START 1 +#define BTC_FOR_SCAN_FINISH 0 + +#define BT_TXRX_CNT_THRES_1 1200 +#define BT_TXRX_CNT_THRES_2 1400 +#define BT_TXRX_CNT_THRES_3 3000 +#define BT_TXRX_CNT_LEVEL_0 0 /* < 1200 */ +#define BT_TXRX_CNT_LEVEL_1 1 /* >= 1200 && < 1400 */ +#define BT_TXRX_CNT_LEVEL_2 2 /* >= 1400 */ +#define BT_TXRX_CNT_LEVEL_3 3 /* >= 3000 */ + +enum bt_state_1ant { + BT_INFO_STATE_DISABLED = 0, + BT_INFO_STATE_NO_CONNECTION = 1, + BT_INFO_STATE_CONNECT_IDLE = 2, + BT_INFO_STATE_INQ_OR_PAG = 3, + BT_INFO_STATE_ACL_ONLY_BUSY = 4, + BT_INFO_STATE_SCO_ONLY_BUSY = 5, + BT_INFO_STATE_ACL_SCO_BUSY = 6, + BT_INFO_STATE_ACL_INQ_OR_PAG = 7, + BT_INFO_STATE_MAX = 8 +}; + +struct btdm_8723a_1ant { + u8 prePsTdma; + u8 curPsTdma; + u8 psTdmaDuAdjType; + u8 bPrePsTdmaOn; + u8 bCurPsTdmaOn; + u8 preWifiPara; + u8 curWifiPara; + u8 preCoexWifiCon; + u8 curCoexWifiCon; + u8 wifiRssiThresh; + + u32 psTdmaMonitorCnt; + u32 psTdmaGlobalCnt; + + /* DurationAdjust For SCO */ + u32 psTdmaMonitorCntForSCO; + u8 psTdmaDuAdjTypeForSCO; + u8 RSSI_WiFi_Last; + u8 RSSI_BT_Last; + + u8 bWiFiHalt; + u8 bRAChanged; +}; + +void BTDM_1AntSignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt); +void BTDM_1AntForDhcp(struct rtw_adapter * padapter); +void BTDM_1AntBtCoexist8723A(struct rtw_adapter * padapter); + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */ +#endif /* __HALBTC87231ANT_C__ */ + +#ifdef __HALBTC87232ANT_C__ /* HAL/BTCoexist/HalBtc87232Ant.h */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */ +enum bt_2ant_bt_status { + BT_2ANT_BT_STATUS_IDLE = 0x0, + BT_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_2ANT_BT_STATUS_MAX +}; + +enum bt_2ant_coex_algo { + BT_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_2ANT_COEX_ALGO_SCO = 0x1, + BT_2ANT_COEX_ALGO_HID = 0x2, + BT_2ANT_COEX_ALGO_A2DP = 0x3, + BT_2ANT_COEX_ALGO_PANEDR = 0x4, + BT_2ANT_COEX_ALGO_PANHS = 0x5, + BT_2ANT_COEX_ALGO_PANEDR_A2DP = 0x6, + BT_2ANT_COEX_ALGO_PANEDR_HID = 0x7, + BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, + BT_2ANT_COEX_ALGO_HID_A2DP = 0x9, + BT_2ANT_COEX_ALGO_HID_A2DP_PANHS = 0xA, + BT_2ANT_COEX_ALGO_MAX = 0xB, +}; + +struct btdm_8723a_2ant { + u8 bPreDecBtPwr; + u8 bCurDecBtPwr; + + u8 preWlanActHi; + u8 curWlanActHi; + u8 preWlanActLo; + u8 curWlanActLo; + + u8 preFwDacSwingLvl; + u8 curFwDacSwingLvl; + + u8 bPreRfRxLpfShrink; + u8 bCurRfRxLpfShrink; + + u8 bPreLowPenaltyRa; + u8 bCurLowPenaltyRa; + + u8 preBtRetryIndex; + u8 curBtRetryIndex; + + u8 bPreDacSwingOn; + u32 preDacSwingLvl; + u8 bCurDacSwingOn; + u32 curDacSwingLvl; + + u8 bPreAdcBackOff; + u8 bCurAdcBackOff; + + u8 bPreAgcTableEn; + u8 bCurAgcTableEn; + + u32 preVal0x6c0; + u32 curVal0x6c0; + u32 preVal0x6c8; + u32 curVal0x6c8; + u8 preVal0x6cc; + u8 curVal0x6cc; + + u8 bCurIgnoreWlanAct; + u8 bPreIgnoreWlanAct; + + u8 prePsTdma; + u8 curPsTdma; + u8 psTdmaDuAdjType; + u8 bPrePsTdmaOn; + u8 bCurPsTdmaOn; + + u8 preAlgorithm; + u8 curAlgorithm; + u8 bResetTdmaAdjust; + + u8 btStatus; +}; + +void BTDM_2AntBtCoexist8723A(struct rtw_adapter * padapter); +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */ +#endif /* __HALBTC87232ANT_C__ */ + +#ifdef __HALBTC8723_C__ /* HAL/BTCoexist/HalBtc8723.h */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */ + +#define BT_Q_PKT_OFF 0 +#define BT_Q_PKT_ON 1 + +#define BT_TX_PWR_OFF 0 +#define BT_TX_PWR_ON 1 + +/* TDMA mode definition */ +#define TDMA_2ANT 0 +#define TDMA_1ANT 1 +#define TDMA_NAV_OFF 0 +#define TDMA_NAV_ON 1 +#define TDMA_DAC_SWING_OFF 0 +#define TDMA_DAC_SWING_ON 1 + +#define BT_RSSI_LEVEL_H 0 +#define BT_RSSI_LEVEL_M 1 +#define BT_RSSI_LEVEL_L 2 + +/* PTA mode related definition */ +#define BT_PTA_MODE_OFF 0 +#define BT_PTA_MODE_ON 1 + +/* Penalty Tx Rate Adaptive */ +#define BT_TX_RATE_ADAPTIVE_NORMAL 0 +#define BT_TX_RATE_ADAPTIVE_LOW_PENALTY 1 + +/* RF Corner */ +#define BT_RF_RX_LPF_CORNER_RESUME 0 +#define BT_RF_RX_LPF_CORNER_SHRINK 1 + +#define BT_INFO_ACL BIT(0) +#define BT_INFO_SCO BIT(1) +#define BT_INFO_INQ_PAG BIT(2) +#define BT_INFO_ACL_BUSY BIT(3) +#define BT_INFO_SCO_BUSY BIT(4) +#define BT_INFO_HID BIT(5) +#define BT_INFO_A2DP BIT(6) +#define BT_INFO_FTP BIT(7) + + + +struct bt_coexist_8723a { + u32 highPriorityTx; + u32 highPriorityRx; + u32 lowPriorityTx; + u32 lowPriorityRx; + u8 btRssi; + u8 TotalAntNum; + u8 bC2hBtInfoSupport; + u8 c2hBtInfo; + u8 c2hBtInfoOriginal; + u8 prec2hBtInfo; /* for 1Ant */ + u8 bC2hBtInquiryPage; + u64 btInqPageStartTime; /* for 2Ant */ + u8 c2hBtProfile; /* for 1Ant */ + u8 btRetryCnt; + u8 btInfoExt; + u8 bC2hBtInfoReqSent; + u8 bForceFwBtInfo; + u8 bForceA2dpSink; + struct btdm_8723a_2ant btdm2Ant; + struct btdm_8723a_1ant btdm1Ant; +}; + +void BTDM_SetFwChnlInfo(struct rtw_adapter * padapter, enum rt_media_status mstatus); +u8 BTDM_IsWifiConnectionExist(struct rtw_adapter * padapter); +void BTDM_SetFw3a(struct rtw_adapter * padapter, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5); +void BTDM_QueryBtInformation(struct rtw_adapter * padapter); +void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter * padapter, u8 type); +void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter * padapter, u8 raType); +void BTDM_SetFwDecBtPwr(struct rtw_adapter * padapter, u8 bDecBtPwr); +u8 BTDM_BtProfileSupport(struct rtw_adapter * padapter); +void BTDM_LpsLeave(struct rtw_adapter * padapter); +u8 BTDM_1Ant8723A(struct rtw_adapter * padapter); +#define BT_1Ant BTDM_1Ant8723A + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */ +#endif /* __HALBTC8723_C__ */ + +#ifdef __HALBTCCSR1ANT_C__ /* HAL/BTCoexist/HalBtcCsr1Ant.h */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */ + +enum BT_A2DP_INDEX{ + BT_A2DP_INDEX0 = 0, /* 32, 12; the most critical for BT */ + BT_A2DP_INDEX1, /* 12, 24 */ + BT_A2DP_INDEX2, /* 0, 0 */ + BT_A2DP_INDEX_MAX +}; + +#define BT_A2DP_STATE_NOT_ENTERED 0 +#define BT_A2DP_STATE_DETECTING 1 +#define BT_A2DP_STATE_DETECTED 2 + +#define BTDM_ANT_BT_IDLE 0 +#define BTDM_ANT_WIFI 1 +#define BTDM_ANT_BT 2 + + +void BTDM_SingleAnt(struct rtw_adapter * padapter, u8 bSingleAntOn, u8 bInterruptOn, u8 bMultiNAVOn); +void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter * padapter); + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */ +#endif /* __HALBTCCSR1ANT_C__ */ + +#ifdef __HALBTCCSR2ANT_C__ /* HAL/BTCoexist/HalBtcCsr2Ant.h */ +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */ + +/* */ +/* For old core stack before v251 */ +/* */ +#define BT_RSSI_STATE_NORMAL_POWER BIT0 +#define BT_RSSI_STATE_AMDPU_OFF BIT1 +#define BT_RSSI_STATE_SPECIAL_LOW BIT2 +#define BT_RSSI_STATE_BG_EDCA_LOW BIT3 +#define BT_RSSI_STATE_TXPOWER_LOW BIT4 + +#define BT_DACSWING_OFF 0 +#define BT_DACSWING_M4 1 +#define BT_DACSWING_M7 2 +#define BT_DACSWING_M10 3 + +void BTDM_DiminishWiFi(struct rtw_adapter * Adapter, u8 bDACOn, u8 bInterruptOn, u8 DACSwingLevel, u8 bNAVOn); + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */ +#endif /* __HALBTCCSR2ANT_C__ */ + +#ifdef __HALBTCOEXIST_C__ /* HAL/BTCoexist/HalBtCoexist.h */ + +/* HEADER/TypeDef.h */ +#define MAX_FW_SUPPORT_MACID_NUM 64 + +/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */ + +#define FW_VER_BT_REG 62 +#define FW_VER_BT_REG1 74 +#define REG_BT_ACTIVE 0x444 +#define REG_BT_STATE 0x448 +#define REG_BT_POLLING1 0x44c +#define REG_BT_POLLING 0x700 + +#define REG_BT_ACTIVE_OLD 0x488 +#define REG_BT_STATE_OLD 0x48c +#define REG_BT_POLLING_OLD 0x490 + +/* The reg define is for 8723 */ +#define REG_HIGH_PRIORITY_TXRX 0x770 +#define REG_LOW_PRIORITY_TXRX 0x774 + +#define BT_FW_COEX_THRESH_TOL 6 +#define BT_FW_COEX_THRESH_20 20 +#define BT_FW_COEX_THRESH_23 23 +#define BT_FW_COEX_THRESH_25 25 +#define BT_FW_COEX_THRESH_30 30 +#define BT_FW_COEX_THRESH_35 35 +#define BT_FW_COEX_THRESH_40 40 +#define BT_FW_COEX_THRESH_45 45 +#define BT_FW_COEX_THRESH_47 47 +#define BT_FW_COEX_THRESH_50 50 +#define BT_FW_COEX_THRESH_55 55 +#define BT_FW_COEX_THRESH_65 65 + +#define BT_COEX_STATE_BT30 BIT(0) +#define BT_COEX_STATE_WIFI_HT20 BIT(1) +#define BT_COEX_STATE_WIFI_HT40 BIT(2) +#define BT_COEX_STATE_WIFI_LEGACY BIT(3) + +#define BT_COEX_STATE_WIFI_RSSI_LOW BIT(4) +#define BT_COEX_STATE_WIFI_RSSI_MEDIUM BIT(5) +#define BT_COEX_STATE_WIFI_RSSI_HIGH BIT(6) +#define BT_COEX_STATE_DEC_BT_POWER BIT(7) + +#define BT_COEX_STATE_WIFI_IDLE BIT(8) +#define BT_COEX_STATE_WIFI_UPLINK BIT(9) +#define BT_COEX_STATE_WIFI_DOWNLINK BIT(10) + +#define BT_COEX_STATE_BT_INQ_PAGE BIT(11) +#define BT_COEX_STATE_BT_IDLE BIT(12) +#define BT_COEX_STATE_BT_UPLINK BIT(13) +#define BT_COEX_STATE_BT_DOWNLINK BIT(14) +/* */ +/* Todo: Remove these definitions */ +#define BT_COEX_STATE_BT_PAN_IDLE BIT(15) +#define BT_COEX_STATE_BT_PAN_UPLINK BIT(16) +#define BT_COEX_STATE_BT_PAN_DOWNLINK BIT(17) +#define BT_COEX_STATE_BT_A2DP_IDLE BIT(18) +/* */ +#define BT_COEX_STATE_BT_RSSI_LOW BIT(19) + +#define BT_COEX_STATE_PROFILE_HID BIT(20) +#define BT_COEX_STATE_PROFILE_A2DP BIT(21) +#define BT_COEX_STATE_PROFILE_PAN BIT(22) +#define BT_COEX_STATE_PROFILE_SCO BIT(23) + +#define BT_COEX_STATE_WIFI_RSSI_1_LOW BIT(24) +#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM BIT(25) +#define BT_COEX_STATE_WIFI_RSSI_1_HIGH BIT(26) + +#define BT_COEX_STATE_WIFI_RSSI_BEACON_LOW BIT(27) +#define BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM BIT(28) +#define BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH BIT(29) + + +#define BT_COEX_STATE_BTINFO_COMMON BIT30 +#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO BIT31 +#define BT_COEX_STATE_BTINFO_B_FTP_A2DP BIT32 + +#define BT_COEX_STATE_BT_CNT_LEVEL_0 BIT33 +#define BT_COEX_STATE_BT_CNT_LEVEL_1 BIT34 +#define BT_COEX_STATE_BT_CNT_LEVEL_2 BIT35 +#define BT_COEX_STATE_BT_CNT_LEVEL_3 BIT36 + +#define BT_RSSI_STATE_HIGH 0 +#define BT_RSSI_STATE_MEDIUM 1 +#define BT_RSSI_STATE_LOW 2 +#define BT_RSSI_STATE_STAY_HIGH 3 +#define BT_RSSI_STATE_STAY_MEDIUM 4 +#define BT_RSSI_STATE_STAY_LOW 5 + +#define BT_AGCTABLE_OFF 0 +#define BT_AGCTABLE_ON 1 + +#define BT_BB_BACKOFF_OFF 0 +#define BT_BB_BACKOFF_ON 1 + +#define BT_FW_NAV_OFF 0 +#define BT_FW_NAV_ON 1 + +#define BT_COEX_MECH_NONE 0 +#define BT_COEX_MECH_SCO 1 +#define BT_COEX_MECH_HID 2 +#define BT_COEX_MECH_A2DP 3 +#define BT_COEX_MECH_PAN 4 +#define BT_COEX_MECH_HID_A2DP 5 +#define BT_COEX_MECH_HID_PAN 6 +#define BT_COEX_MECH_PAN_A2DP 7 +#define BT_COEX_MECH_HID_SCO_ESCO 8 +#define BT_COEX_MECH_FTP_A2DP 9 +#define BT_COEX_MECH_COMMON 10 +#define BT_COEX_MECH_MAX 11 +/* BT Dbg Ctrl */ +#define BT_DBG_PROFILE_NONE 0 +#define BT_DBG_PROFILE_SCO 1 +#define BT_DBG_PROFILE_HID 2 +#define BT_DBG_PROFILE_A2DP 3 +#define BT_DBG_PROFILE_PAN 4 +#define BT_DBG_PROFILE_HID_A2DP 5 +#define BT_DBG_PROFILE_HID_PAN 6 +#define BT_DBG_PROFILE_PAN_A2DP 7 +#define BT_DBG_PROFILE_MAX 9 + +struct bt_coexist_str { + u8 BluetoothCoexist; + u8 BT_Ant_Num; + u8 BT_CoexistType; + u8 BT_Ant_isolation; /* 0:good, 1:bad */ + u8 bt_radiosharedtype; + u32 Ratio_Tx; + u32 Ratio_PRI; + u8 bInitlized; + u32 BtRfRegOrigin1E; + u32 BtRfRegOrigin1F; + u8 bBTBusyTraffic; + u8 bBTTrafficModeSet; + u8 bBTNonTrafficModeSet; + struct bt_traffic_statistics BT21TrafficStatistics; + u64 CurrentState; + u64 PreviousState; + u8 preRssiState; + u8 preRssiState1; + u8 preRssiStateBeacon; + u8 bFWCoexistAllOff; + u8 bSWCoexistAllOff; + u8 bHWCoexistAllOff; + u8 bBalanceOn; + u8 bSingleAntOn; + u8 bInterruptOn; + u8 bMultiNAVOn; + u8 PreWLANActH; + u8 PreWLANActL; + u8 WLANActH; + u8 WLANActL; + u8 A2DPState; + u8 AntennaState; + u32 lastBtEdca; + u16 last_aggr_num; + u8 bEDCAInitialized; + u8 exec_cnt; + u8 b8723aAgcTableOn; + u8 b92DAgcTableOn; + struct bt_coexist_8723a halCoex8723; + u8 btActiveZeroCnt; + u8 bCurBtDisabled; + u8 bPreBtDisabled; + u8 bNeedToRoamForBtDisableEnable; + u8 fw3aVal[5]; +}; + +void BTDM_CheckAntSelMode(struct rtw_adapter * padapter); +void BTDM_FwC2hBtRssi(struct rtw_adapter * padapter, u8 *tmpBuf); +#define BT_FwC2hBtRssi BTDM_FwC2hBtRssi +void BTDM_FwC2hBtInfo(struct rtw_adapter * padapter, u8 *tmpBuf, u8 length); +#define BT_FwC2hBtInfo BTDM_FwC2hBtInfo +void BTDM_DisplayBtCoexInfo(struct rtw_adapter * padapter); +#define BT_DisplayBtCoexInfo BTDM_DisplayBtCoexInfo +void BTDM_RejectAPAggregatedPacket(struct rtw_adapter * padapter, u8 bReject); +u8 BTDM_IsHT40(struct rtw_adapter * padapter); +u8 BTDM_Legacy(struct rtw_adapter * padapter); +void BTDM_CheckWiFiState(struct rtw_adapter * padapter); +s32 BTDM_GetRxSS(struct rtw_adapter * padapter); +u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); +u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); +u8 BTDM_CheckCoexRSSIState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1); +u8 BTDM_DisableEDCATurbo(struct rtw_adapter * padapter); +#define BT_DisableEDCATurbo BTDM_DisableEDCATurbo +void BTDM_Balance(struct rtw_adapter * padapter, u8 bBalanceOn, u8 ms0, u8 ms1); +void BTDM_AGCTable(struct rtw_adapter * padapter, u8 type); +void BTDM_BBBackOffLevel(struct rtw_adapter * padapter, u8 type); +void BTDM_FWCoexAllOff(struct rtw_adapter * padapter); +void BTDM_SWCoexAllOff(struct rtw_adapter * padapter); +void BTDM_HWCoexAllOff(struct rtw_adapter * padapter); +void BTDM_CoexAllOff(struct rtw_adapter * padapter); +void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter * padapter); +void BTDM_SignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt); +void BTDM_Coexist(struct rtw_adapter * padapter); +#define BT_CoexistMechanism BTDM_Coexist +void BTDM_UpdateCoexState(struct rtw_adapter * padapter); +u8 BTDM_IsSameCoexistState(struct rtw_adapter * padapter); +void BTDM_PWDBMonitor(struct rtw_adapter * padapter); +u8 BTDM_IsBTBusy(struct rtw_adapter * padapter); +#define BT_IsBtBusy BTDM_IsBTBusy +u8 BTDM_IsWifiBusy(struct rtw_adapter * padapter); +u8 BTDM_IsCoexistStateChanged(struct rtw_adapter * padapter); +u8 BTDM_IsWifiUplink(struct rtw_adapter * padapter); +u8 BTDM_IsWifiDownlink(struct rtw_adapter * padapter); +u8 BTDM_IsBTHSMode(struct rtw_adapter * padapter); +u8 BTDM_IsBTUplink(struct rtw_adapter * padapter); +u8 BTDM_IsBTDownlink(struct rtw_adapter * padapter); +void BTDM_AdjustForBtOperation(struct rtw_adapter * padapter); +void BTDM_ForHalt(struct rtw_adapter * padapter); +void BTDM_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType); +void BTDM_WifiAssociateNotify(struct rtw_adapter * padapter, u8 action); +void BTDM_MediaStatusNotify(struct rtw_adapter * padapter, enum rt_media_status mstatus); +void BTDM_ForDhcp(struct rtw_adapter * padapter); +void BTDM_ResetActionProfileState(struct rtw_adapter * padapter); +void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter * padapter, u8 antNum); +#define BT_SetBtCoexCurrAntNum BTDM_SetBtCoexCurrAntNum +u8 BTDM_IsActionSCO(struct rtw_adapter * padapter); +u8 BTDM_IsActionHID(struct rtw_adapter * padapter); +u8 BTDM_IsActionA2DP(struct rtw_adapter * padapter); +u8 BTDM_IsActionPAN(struct rtw_adapter * padapter); +u8 BTDM_IsActionHIDA2DP(struct rtw_adapter * padapter); +u8 BTDM_IsActionHIDPAN(struct rtw_adapter * padapter); +u8 BTDM_IsActionPANA2DP(struct rtw_adapter * padapter); +u8 BTDM_IsBtDisabled(struct rtw_adapter * padapter); +#define BT_IsBtDisabled BTDM_IsBtDisabled +u32 BTDM_BtTxRxCounterH(struct rtw_adapter * padapter); +u32 BTDM_BtTxRxCounterL(struct rtw_adapter * padapter); + +/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */ +#endif /* __HALBTCOEXIST_C__ */ + +#ifdef __HALBT_C__ /* HAL/HalBT.h */ +/* ===== Below this line is sync from SD7 driver HAL/HalBT.h ===== */ + +#define RTS_CTS_NO_LEN_LIMIT 0 + +u8 HALBT_GetPGAntNum(struct rtw_adapter * padapter); +#define BT_GetPGAntNum HALBT_GetPGAntNum +void HALBT_SetKey(struct rtw_adapter * padapter, u8 EntryNum); +void HALBT_RemoveKey(struct rtw_adapter * padapter, u8 EntryNum); +void HALBT_InitBTVars8723A(struct rtw_adapter * padapter); +#define HALBT_InitHalVars HALBT_InitBTVars8723A +#define BT_InitHalVars HALBT_InitHalVars +u8 HALBT_IsBTExist(struct rtw_adapter * padapter); +#define BT_IsBtExist HALBT_IsBTExist +u8 HALBT_BTChipType(struct rtw_adapter * padapter); +void HALBT_InitHwConfig(struct rtw_adapter * padapter); +#define BT_InitHwConfig HALBT_InitHwConfig +void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter * padapter); + +/* ===== End of sync from SD7 driver HAL/HalBT.c ===== */ +#endif /* __HALBT_C__ */ + +#define _bt_dbg_off_ 0 +#define _bt_dbg_on_ 1 + +extern u32 BTCoexDbgLevel; + + + +#endif /* __RTL8723A_BT_COEXIST_H__ */ diff --git a/drivers/staging/rtl8723au/include/rtl8723a_cmd.h b/drivers/staging/rtl8723au/include/rtl8723a_cmd.h new file mode 100644 index 000000000000..8fccbfc3a45c --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_cmd.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_CMD_H__ +#define __RTL8723A_CMD_H__ + + +#define H2C_BT_FW_PATCH_LEN 3 +#define H2C_BT_PWR_FORCE_LEN 3 + +enum cmd_msg_element_id +{ + NONE_CMDMSG_EID, + AP_OFFLOAD_EID = 0, + SET_PWRMODE_EID = 1, + JOINBSS_RPT_EID = 2, + RSVD_PAGE_EID = 3, + RSSI_4_EID = 4, + RSSI_SETTING_EID = 5, + MACID_CONFIG_EID = 6, + MACID_PS_MODE_EID = 7, + P2P_PS_OFFLOAD_EID = 8, + SELECTIVE_SUSPEND_ROF_CMD = 9, + BT_QUEUE_PKT_EID = 17, + BT_ANT_TDMA_EID = 20, + BT_2ANT_HID_EID = 21, + P2P_PS_CTW_CMD_EID = 32, + FORCE_BT_TX_PWR_EID = 33, + SET_TDMA_WLAN_ACT_TIME_EID = 34, + SET_BT_TX_RETRY_INDEX_EID = 35, + HID_PROFILE_ENABLE_EID = 36, + BT_IGNORE_WLAN_ACT_EID = 37, + BT_PTA_MANAGER_UPDATE_ENABLE_EID = 38, + DAC_SWING_VALUE_EID = 41, + TRADITIONAL_TDMA_EN_EID = 51, + H2C_BT_FW_PATCH = 54, + B_TYPE_TDMA_EID = 58, + SCAN_EN_EID = 59, + LOWPWR_LPS_EID = 71, + H2C_RESET_TSF = 75, + MAX_CMDMSG_EID +}; + +struct cmd_msg_parm { + u8 eid; /* element id */ + u8 sz; /* sz */ + u8 buf[6]; +}; + +struct setpwrmode_parm { + u8 Mode; + u8 SmartPS; + u8 AwakeInterval; /* unit: beacon interval */ + u8 bAllQueueUAPSD; + +#define SETPM_LOWRXBCN BIT(0) +#define SETPM_AUTOANTSWITCH BIT(1) +#define SETPM_PSALLOWBTHIGHPRI BIT(2) + u8 BcnAntMode; +} __packed; + +struct H2C_SS_RFOFF_PARAM{ + u8 ROFOn; /* 1: on, 0:off */ + u16 gpio_period; /* unit: 1024 us */ +}__attribute__ ((packed)); + + +struct joinbssrpt_parm { + u8 OpMode; /* enum rt_media_status */ +}; + +struct rsvdpage_loc { + u8 LocProbeRsp; + u8 LocPsPoll; + u8 LocNullData; + u8 LocQosNull; + u8 LocBTQosNull; +}; + +struct P2P_PS_Offload_t { + u8 Offload_En:1; + u8 role:1; /* 1: Owner, 0: Client */ + u8 CTWindow_En:1; + u8 NoA0_En:1; + u8 NoA1_En:1; + u8 AllStaSleep:1; /* Only valid in Owner */ + u8 discovery:1; + u8 rsvd:1; +}; + +struct P2P_PS_CTWPeriod_t { + u8 CTWPeriod; /* TU */ +}; + +#define B_TDMA_EN BIT(0) +#define B_TDMA_FIXANTINBT BIT(1) +#define B_TDMA_TXPSPOLL BIT(2) +#define B_TDMA_VAL870 BIT(3) +#define B_TDMA_AUTOWAKEUP BIT(4) +#define B_TDMA_NOPS BIT(5) +#define B_TDMA_WLANHIGHPRI BIT(6) + +struct b_type_tdma_parm { + u8 option; + + u8 TBTTOnPeriod; + u8 MedPeriod; + u8 rsvd30; +} __packed; + +struct scan_en_parm { + u8 En; +} __packed; + +/* BT_PWR */ +#define SET_H2CCMD_BT_PWR_IDX(__pH2CCmd, __Value) SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value) + +/* BT_FW_PATCH */ +#define SET_H2CCMD_BT_FW_PATCH_ENABLE(__pH2CCmd, __Value) SET_BITS_TO_LE_4BYTE(__pH2CCmd, 0, 8, __Value) /* SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) */ +#define SET_H2CCMD_BT_FW_PATCH_SIZE(__pH2CCmd, __Value) SET_BITS_TO_LE_4BYTE(__pH2CCmd, 8, 16, __Value) /* SET_BITS_TO_LE_2BYTE((__pH2CCmd)+1, 0, 16, __Value) */ + +struct lowpwr_lps_parm{ + u8 bcn_count:4; + u8 tb_bcn_threshold:3; + u8 enable:1; + u8 bcn_interval; + u8 drop_threshold; + u8 max_early_period; + u8 max_bcn_timeout_period; +} __packed; + + +/* host message to firmware cmd */ +void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter * padapter, u8 Mode); +void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter * padapter, u8 mstatus); +#ifdef CONFIG_8723AU_BT_COEXIST +void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter * padapter); +#endif +u8 rtl8723a_set_rssi_cmd(struct rtw_adapter * padapter, u8 *param); +u8 rtl8723a_set_raid_cmd(struct rtw_adapter * padapter, u32 mask, u8 arg); +void rtl8723a_add_rateatid(struct rtw_adapter * padapter, u32 bitmap, u8 arg, u8 rssi_level); + +#ifdef CONFIG_8723AU_P2P +void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter * padapter, u8 p2p_ps_state); +#endif /* CONFIG_8723AU_P2P */ + +void CheckFwRsvdPageContent23a(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_dm.h b/drivers/staging/rtl8723au/include/rtl8723a_dm.h new file mode 100644 index 000000000000..47e887f5bb26 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_dm.h @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_DM_H__ +#define __RTL8723A_DM_H__ +/* */ +/* Description: */ +/* */ +/* This file is for 8723A dynamic mechanism only */ +/* */ +/* */ +/* */ +#define DYNAMIC_FUNC_BT BIT(0) + +enum{ + UP_LINK, + DOWN_LINK, +}; +/* */ +/* structure and define */ +/* */ + +/* duplicate code,will move to ODM ######### */ +#define IQK_MAC_REG_NUM 4 +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 9 +#define HP_THERMAL_NUM 8 +/* duplicate code,will move to ODM ######### */ +struct dm_priv +{ + u8 DM_Type; + u8 DMFlag; + u8 InitDMFlag; + u32 InitODMFlag; + + /* Upper and Lower Signal threshold for Rate Adaptive*/ + int UndecoratedSmoothedPWDB; + int UndecoratedSmoothedCCK; + int EntryMinUndecoratedSmoothedPWDB; + int EntryMaxUndecoratedSmoothedPWDB; + int MinUndecoratedPWDBForDM; + int LastMinUndecoratedPWDBForDM; + + s32 UndecoratedSmoothedBeacon; + #ifdef CONFIG_8723AU_BT_COEXIST + s32 BT_EntryMinUndecoratedSmoothedPWDB; + s32 BT_EntryMaxUndecoratedSmoothedPWDB; + #endif + + /* for High Power */ + u8 bDynamicTxPowerEnable; + u8 LastDTPLvl; + u8 DynamicTxHighPowerLvl;/* Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 */ + + /* for tx power tracking */ + u8 bTXPowerTracking; + u8 TXPowercount; + u8 bTXPowerTrackingInit; + u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */ + u8 TM_Trigger; + + u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ + u8 ThermalValue; + u8 ThermalValue_LCK; + u8 ThermalValue_IQK; + u8 ThermalValue_DPK; + + u8 bRfPiEnable; + + /* for APK */ + u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ + u8 bAPKdone; + u8 bAPKThermalMeterIgnore; + u8 bDPdone; + u8 bDPPathAOK; + u8 bDPPathBOK; + + /* for IQK */ + u32 RegC04; + u32 Reg874; + u32 RegC08; + u32 RegB68; + u32 RegB6C; + u32 Reg870; + u32 Reg860; + u32 Reg864; + u32 ADDA_backup[IQK_ADDA_REG_NUM]; + u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; + u32 IQK_BB_backup_recover[9]; + u32 IQK_BB_backup[IQK_BB_REG_NUM]; + u8 PowerIndex_backup[6]; + + u8 bCCKinCH14; + + u8 CCK_index; + u8 OFDM_index[2]; + + u8 bDoneTxpower; + u8 CCK_index_HP; + u8 OFDM_index_HP[2]; + u8 ThermalValue_HP[HP_THERMAL_NUM]; + u8 ThermalValue_HP_index; + + /* for TxPwrTracking */ + s32 RegE94; + s32 RegE9C; + s32 RegEB4; + s32 RegEBC; + + u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ + + u32 prv_traffic_idx; /* edca turbo */ + + s32 OFDM_Pkt_Cnt; + u8 RSSI_Select; +/* u8 DIG_Dynamic_MIN ; */ +/* duplicate code,will move to ODM ######### */ + /* Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas */ + u8 INIDATA_RATE[32]; +}; + + +/* */ +/* function prototype */ +/* */ + +void rtl8723a_init_dm_priv(struct rtw_adapter *padapter); +void rtl8723a_deinit_dm_priv(struct rtw_adapter *padapter); + +void rtl8723a_InitHalDm(struct rtw_adapter *padapter); +void rtl8723a_HalDmWatchDog(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_hal.h b/drivers/staging/rtl8723au/include/rtl8723a_hal.h new file mode 100644 index 000000000000..c20248bab717 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_hal.h @@ -0,0 +1,575 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_HAL_H__ +#define __RTL8723A_HAL_H__ + +#include "rtl8723a_spec.h" +#include "rtl8723a_pg.h" +#include "Hal8723APhyReg.h" +#include "Hal8723APhyCfg.h" +#include "rtl8723a_rf.h" +#ifdef CONFIG_8723AU_BT_COEXIST +#include "rtl8723a_bt-coexist.h" +#endif +#include "rtl8723a_dm.h" +#include "rtl8723a_recv.h" +#include "rtl8723a_xmit.h" +#include "rtl8723a_cmd.h" +#include "rtl8723a_sreset.h" +#include "rtw_efuse.h" + +#include "odm_precomp.h" + + +/* 2TODO: We should define 8192S firmware related macro settings here!! */ +#define RTL819X_DEFAULT_RF_TYPE RF_1T2R +#define RTL819X_TOTAL_RF_PATH 2 + +/* TODO: The following need to check!! */ +#define RTL8723_FW_UMC_IMG "rtl8192CU\\rtl8723fw.bin" +#define RTL8723_FW_UMC_B_IMG "rtl8192CU\\rtl8723fw_B.bin" +#define RTL8723_PHY_REG "rtl8723S\\PHY_REG_1T.txt" +#define RTL8723_PHY_RADIO_A "rtl8723S\\radio_a_1T.txt" +#define RTL8723_PHY_RADIO_B "rtl8723S\\radio_b_1T.txt" +#define RTL8723_AGC_TAB "rtl8723S\\AGC_TAB_1T.txt" +#define RTL8723_PHY_MACREG "rtl8723S\\MAC_REG.txt" +#define RTL8723_PHY_REG_PG "rtl8723S\\PHY_REG_PG.txt" +#define RTL8723_PHY_REG_MP "rtl8723S\\PHY_REG_MP.txt" + +/* */ +/* RTL8723S From header */ +/* */ + +/* Fw Array */ +#define Rtl8723_FwImageArray Rtl8723UFwImgArray +#define Rtl8723_FwUMCBCutImageArrayWithBT Rtl8723UFwUMCBCutImgArrayWithBT +#define Rtl8723_FwUMCBCutImageArrayWithoutBT Rtl8723UFwUMCBCutImgArrayWithoutBT + +#define Rtl8723_ImgArrayLength Rtl8723UImgArrayLength +#define Rtl8723_UMCBCutImgArrayWithBTLength Rtl8723UUMCBCutImgArrayWithBTLength +#define Rtl8723_UMCBCutImgArrayWithoutBTLength Rtl8723UUMCBCutImgArrayWithoutBTLength + +#define Rtl8723_PHY_REG_Array_PG Rtl8723UPHY_REG_Array_PG +#define Rtl8723_PHY_REG_Array_PGLength Rtl8723UPHY_REG_Array_PGLength + +#define Rtl8723_FwUMCBCutMPImageArray Rtl8723SFwUMCBCutMPImgAr +#define Rtl8723_UMCBCutMPImgArrayLength Rtl8723SUMCBCutMPImgArrayLength + +#define DRVINFO_SZ 4 /* unit is 8bytes */ +#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0)) + +#define FW_8723A_SIZE 0x8000 +#define FW_8723A_START_ADDRESS 0x1000 +#define FW_8723A_END_ADDRESS 0x1FFF /* 0x5FFF */ + +#define MAX_PAGE_SIZE 4096 /* @ page : 4k bytes */ + +#define IS_FW_HEADER_EXIST(_pFwHdr) ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\ + (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\ + (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300) + +/* */ +/* This structure must be cared byte-ordering */ +/* */ +/* Added by tynli. 2009.12.04. */ +struct rt_8723a_firmware_hdr { + /* 8-byte alinment required */ + + /* LONG WORD 0 ---- */ + u16 Signature; /* 92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut */ + u8 Category; /* AP/NIC and USB/PCI */ + u8 Function; /* Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions */ + u16 Version; /* FW Version */ + u8 Subversion; /* FW Subversion, default 0x00 */ + u16 Rsvd1; + + + /* LONG WORD 1 ---- */ + u8 Month; /* Release time Month field */ + u8 Date; /* Release time Date field */ + u8 Hour; /* Release time Hour field */ + u8 Minute; /* Release time Minute field */ + u16 RamCodeSize; /* The size of RAM code */ + u16 Rsvd2; + + /* LONG WORD 2 ---- */ + u32 SvnIdx; /* The SVN entry index */ + u32 Rsvd3; + + /* LONG WORD 3 ---- */ + u32 Rsvd4; + u32 Rsvd5; +}; + +#define DRIVER_EARLY_INT_TIME 0x05 +#define BCN_DMA_ATIME_INT_TIME 0x02 + + +/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ +#define MAX_TX_QUEUE 9 + +#define TX_SELE_HQ BIT(0) /* High Queue */ +#define TX_SELE_LQ BIT(1) /* Low Queue */ +#define TX_SELE_NQ BIT(2) /* Normal Queue */ + +/* Note: We will divide number of page equally for each queue other than public queue! */ +#define TX_TOTAL_PAGE_NUMBER 0xF8 +#define TX_PAGE_BOUNDARY (TX_TOTAL_PAGE_NUMBER + 1) + +/* For Normal Chip Setting */ +/* (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER */ +#define NORMAL_PAGE_NUM_PUBQ 0xE7 +#define NORMAL_PAGE_NUM_HPQ 0x0C +#define NORMAL_PAGE_NUM_LPQ 0x02 +#define NORMAL_PAGE_NUM_NPQ 0x02 + +/* For Test Chip Setting */ +/* (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER */ +#define TEST_PAGE_NUM_PUBQ 0x7E + +/* For Test Chip Setting */ +#define WMM_TEST_TX_TOTAL_PAGE_NUMBER 0xF5 +#define WMM_TEST_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */ + +#define WMM_TEST_PAGE_NUM_PUBQ 0xA3 +#define WMM_TEST_PAGE_NUM_HPQ 0x29 +#define WMM_TEST_PAGE_NUM_LPQ 0x29 + +/* Note: For Normal Chip Setting, modify later */ +#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER 0xF5 +#define WMM_NORMAL_TX_PAGE_BOUNDARY (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */ + +#define WMM_NORMAL_PAGE_NUM_PUBQ 0xB0 +#define WMM_NORMAL_PAGE_NUM_HPQ 0x29 +#define WMM_NORMAL_PAGE_NUM_LPQ 0x1C +#define WMM_NORMAL_PAGE_NUM_NPQ 0x1C + + +/* */ +/* Chip specific */ +/* */ +#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) +#define CHIP_BONDING_92C_1T2R 0x1 +#define CHIP_BONDING_88C_USB_MCARD 0x2 +#define CHIP_BONDING_88C_USB_HP 0x1 + +#include "HalVerDef.h" +#include "hal_com.h" + +/* */ +/* Channel Plan */ +/* */ +enum ChannelPlan +{ + CHPL_FCC = 0, + CHPL_IC = 1, + CHPL_ETSI = 2, + CHPL_SPAIN = 3, + CHPL_FRANCE = 4, + CHPL_MKK = 5, + CHPL_MKK1 = 6, + CHPL_ISRAEL = 7, + CHPL_TELEC = 8, + CHPL_GLOBAL = 9, + CHPL_WORLD = 10, +}; + +#define EFUSE_REAL_CONTENT_LEN 512 +#define EFUSE_MAP_LEN 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_IC_ID_OFFSET 506 /* For some inferiority IC purpose. added by Roger, 2009.09.02. */ +#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN) +/* */ +/* */ +/* To prevent out of boundary programming case, */ +/* leave 1byte and program full section */ +/* 9bytes + 1byt + 5bytes and pre 1byte. */ +/* For worst case: */ +/* | 1byte|----8bytes----|1byte|--5bytes--| */ +/* | | Reserved(14bytes) | */ +/* */ + +/* PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. */ +#define EFUSE_OOB_PROTECT_BYTES 15 + +#define EFUSE_REAL_CONTENT_LEN_8723A 512 +#define EFUSE_MAP_LEN_8723A 256 +#define EFUSE_MAX_SECTION_8723A 32 + +/* */ +/* EFUSE for BT definition */ +/* */ +#define EFUSE_BT_REAL_BANK_CONTENT_LEN 512 +#define EFUSE_BT_REAL_CONTENT_LEN 1536 /* 512*3 */ +#define EFUSE_BT_MAP_LEN 1024 /* 1k bytes */ +#define EFUSE_BT_MAX_SECTION 128 /* 1024/8 */ + +#define EFUSE_PROTECT_BYTES_BANK 16 + +/* */ +/* For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. */ +/* */ +enum RT_MULTI_FUNC { + RT_MULTI_FUNC_NONE = 0x00, + RT_MULTI_FUNC_WIFI = 0x01, + RT_MULTI_FUNC_BT = 0x02, + RT_MULTI_FUNC_GPS = 0x04, +}; + +/* */ +/* For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. */ +/* */ +enum RT_POLARITY_CTL { + RT_POLARITY_LOW_ACT = 0, + RT_POLARITY_HIGH_ACT = 1, +}; + +/* For RTL8723 regulator mode. by tynli. 2011.01.14. */ +enum RT_REGULATOR_MODE { + RT_SWITCHING_REGULATOR = 0, + RT_LDO_REGULATOR = 1, +}; + +/* Description: Determine the types of C2H events that are the same in driver and Fw. */ +/* Fisrt constructed by tynli. 2009.10.09. */ +enum { + C2H_DBG = 0, + C2H_TSF = 1, + C2H_AP_RPT_RSP = 2, + C2H_CCX_TX_RPT = 3, /* The FW notify the report of the specific tx packet. */ + C2H_BT_RSSI = 4, + C2H_BT_OP_MODE = 5, + C2H_EXT_RA_RPT = 6, + C2H_HW_INFO_EXCH = 10, + C2H_C2H_H2C_TEST = 11, + C2H_BT_INFO = 12, + C2H_BT_MP_INFO = 15, + MAX_C2HEVENT +}; + +struct hal_data_8723a { + struct hal_version VersionID; + enum rt_customer_id CustomerID; + + u16 FirmwareVersion; + u16 FirmwareVersionRev; + u16 FirmwareSubVersion; + u16 FirmwareSignature; + + /* current WIFI_PHY values */ + u32 ReceiveConfig; + enum WIRELESS_MODE CurrentWirelessMode; + enum ht_channel_width CurrentChannelBW; + u8 CurrentChannel; + u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */ + + u16 BasicRateSet; + + /* rf_ctrl */ + u8 rf_chip; + u8 rf_type; + u8 NumTotalRFPath; + + u8 BoardType; + u8 CrystalCap; + /* */ + /* EEPROM setting. */ + /* */ + u8 EEPROMVersion; + u16 EEPROMVID; + u16 EEPROMPID; + u16 EEPROMSVID; + u16 EEPROMSDID; + u8 EEPROMCustomerID; + u8 EEPROMSubCustomerID; + u8 EEPROMRegulatory; + u8 EEPROMThermalMeter; + u8 EEPROMBluetoothCoexist; + u8 EEPROMBluetoothType; + u8 EEPROMBluetoothAntNum; + u8 EEPROMBluetoothAntIsolation; + u8 EEPROMBluetoothRadioShared; + + u8 bTXPowerDataReadFromEEPORM; + u8 bAPKThermalMeterIgnore; + + u8 bIQKInitialized; + u8 bAntennaDetected; + + u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; + u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; /* For HT 40MHZ pwr */ + u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; /* For HT 40MHZ pwr */ + u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];/* HT 20<->40 Pwr diff */ + u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];/* For HT<->legacy pwr diff */ + /* For power group */ + u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; + u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; + + u8 LegacyHTTxPowerDiff;/* Legacy to HT rate power diff */ + + /* Read/write are allow for following hardware information variables */ + u8 framesync; + u32 framesyncC34; + u8 framesyncMonitor; + u8 DefaultInitialGain[4]; + u8 pwrGroupCnt; + u32 MCSTxPowerLevelOriginalOffset[7][16]; + u32 CCKTxPowerLevelOriginalOffset; + + u32 AntennaTxPath; /* Antenna path Tx */ + u32 AntennaRxPath; /* Antenna path Rx */ + u8 ExternalPA; + + u8 bLedOpenDrain; /* Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. */ + + u8 b1x1RecvCombine; /* for 1T1R receive combining */ + + /* For EDCA Turbo mode */ + + u32 AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */ + + /* vivi, for tx power tracking, 20080407 */ + /* u16 TSSI_13dBm; */ + /* u32 Pwr_Track; */ + /* The current Tx Power Level */ + u8 CurrentCckTxPwrIdx; + u8 CurrentOfdm24GTxPwrIdx; + + struct bb_reg_define PHYRegDef[4]; /* Radio A/B/C/D */ + + bool bRFPathRxEnable[4]; /* We support 4 RF path now. */ + + u32 RfRegChnlVal[2]; + + u8 bCckHighPower; + + /* RDG enable */ + bool bRDGEnable; + + /* for host message to fw */ + u8 LastHMEBoxNum; + + u8 fw_ractrl; + u8 RegTxPause; + /* Beacon function related global variable. */ + u32 RegBcnCtrlVal; + u8 RegFwHwTxQCtrl; + u8 RegReg542; + + struct dm_priv dmpriv; + struct dm_odm_t odmpriv; + struct sreset_priv srestpriv; + +#ifdef CONFIG_8723AU_BT_COEXIST + u8 bBTMode; + /* BT only. */ + struct bt_30info BtInfo; + /* For bluetooth co-existance */ + struct bt_coexist_str bt_coexist; +#endif + + u8 bDumpRxPkt;/* for debug */ + u8 FwRsvdPageStartOffset; /* 2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. */ + + /* 2010/08/09 MH Add CU power down mode. */ + u8 pwrdown; + + /* Add for dual MAC 0--Mac0 1--Mac1 */ + u32 interfaceIndex; + + u8 OutEpQueueSel; + u8 OutEpNumber; + + /* 2010/12/10 MH Add for USB aggreation mode dynamic shceme. */ + bool UsbRxHighSpeedMode; + + /* 2010/11/22 MH Add for slim combo debug mode selective. */ + /* This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. */ + bool SlimComboDbg; + + /* */ + /* Add For EEPROM Efuse switch and Efuse Shadow map Setting */ + /* */ + u8 EepromOrEfuse; + u16 EfuseUsedBytes; + u16 BTEfuseUsedBytes; + + /* Interrupt relatd register information. */ + u32 SysIntrStatus; + u32 SysIntrMask; + + /* */ + /* 2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an */ + /* independent file in the future. */ + /* */ + /* 8723-----------------------------------------*/ + enum RT_MULTI_FUNC MultiFunc; /* For multi-function consideration. */ + enum RT_POLARITY_CTL PolarityCtl; /* For Wifi PDn Polarity control. */ + enum RT_REGULATOR_MODE RegulatorMode; /* switching regulator or LDO */ + /* 8723----------------------------------------- + * 2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an */ + /* independent file in the future. */ + + bool bMACFuncEnable; + +#ifdef CONFIG_8723AU_P2P + struct P2P_PS_Offload_t p2p_ps_offload; +#endif + + + /* */ + /* For USB Interface HAL related */ + /* */ + u32 UsbBulkOutSize; + + /* Interrupt related register information. */ + u32 IntArray[2]; + u32 IntrMask[2]; + + /* */ + /* For SDIO Interface HAL related */ + /* */ + + /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */ + u8 bMacPwrCtrlOn; + +}; + +#define GET_HAL_DATA(__pAdapter) ((struct hal_data_8723a *)((__pAdapter)->HalData)) +#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) + +#define INCLUDE_MULTI_FUNC_BT(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) +#define INCLUDE_MULTI_FUNC_GPS(_Adapter) (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) + +struct rxreport_8723a { + u32 pktlen:14; + u32 crc32:1; + u32 icverr:1; + u32 drvinfosize:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 physt:1; + u32 swdec:1; + u32 ls:1; + u32 fs:1; + u32 eor:1; + u32 own:1; + + u32 macid:5; + u32 tid:4; + u32 hwrsvd:4; + u32 amsdu:1; + u32 paggr:1; + u32 faggr:1; + u32 a1fit:4; + u32 a2fit:4; + u32 pam:1; + u32 pwr:1; + u32 md:1; + u32 mf:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd0831:1; + + u32 rxmcs:6; + u32 rxht:1; + u32 gf:1; + u32 splcp:1; + u32 bw:1; + u32 htc:1; + u32 eosp:1; + u32 bssidfit:2; + u32 rsvd1214:16; + u32 unicastwake:1; + u32 magicwake:1; + + u32 pattern0match:1; + u32 pattern1match:1; + u32 pattern2match:1; + u32 pattern3match:1; + u32 pattern4match:1; + u32 pattern5match:1; + u32 pattern6match:1; + u32 pattern7match:1; + u32 pattern8match:1; + u32 pattern9match:1; + u32 patternamatch:1; + u32 patternbmatch:1; + u32 patterncmatch:1; + u32 rsvd1613:19; + + u32 tsfl; + + u32 bassn:12; + u32 bavld:1; + u32 rsvd2413:19; +}; + +/* rtl8723a_hal_init.c */ +s32 rtl8723a_FirmwareDownload(struct rtw_adapter *padapter); +void rtl8723a_FirmwareSelfReset(struct rtw_adapter *padapter); +void rtl8723a_InitializeFirmwareVars(struct rtw_adapter *padapter); + +void rtl8723a_InitAntenna_Selection(struct rtw_adapter *padapter); +void rtl8723a_DeinitAntenna_Selection(struct rtw_adapter *padapter); +void rtl8723a_CheckAntenna_Selection(struct rtw_adapter *padapter); +void rtl8723a_init_default_value(struct rtw_adapter *padapter); + +s32 InitLLTTable23a(struct rtw_adapter *padapter, u32 boundary); + +s32 CardDisableHWSM(struct rtw_adapter *padapter, u8 resetMCU); +s32 CardDisableWithoutHWSM(struct rtw_adapter *padapter); + +/* EFuse */ +u8 GetEEPROMSize8723A(struct rtw_adapter *padapter); +void Hal_InitPGData(struct rtw_adapter *padapter, u8 *PROMContent); +void Hal_EfuseParseIDCode(struct rtw_adapter *padapter, u8 *hwinfo); +void Hal_EfuseParsetxpowerinfo_8723A(struct rtw_adapter *padapter, u8 *PROMContent, bool AutoLoadFail); +void Hal_EfuseParseBTCoexistInfo_8723A(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void Hal_EfuseParseEEPROMVer(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void rtl8723a_EfuseParseChnlPlan(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void Hal_EfuseParseCustomerID(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void Hal_EfuseParseAntennaDiversity(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void Hal_EfuseParseRateIndicationOption(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail); +void Hal_EfuseParseXtal_8723A(struct rtw_adapter *pAdapter, u8 *hwinfo, u8 AutoLoadFail); +void Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter, u8 *hwinfo, u8 AutoLoadFail); + +void Hal_InitChannelPlan23a(struct rtw_adapter *padapter); + +void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc); +void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val); +void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val); +#ifdef CONFIG_8723AU_BT_COEXIST +void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter); +#endif + +/* register */ +void SetBcnCtrlReg23a(struct rtw_adapter *padapter, u8 SetBits, u8 ClearBits); +void rtl8723a_InitBeaconParameters(struct rtw_adapter *padapter); + +void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter, struct rtw_adapter *src_adapter); +void rtl8723a_start_thread(struct rtw_adapter *padapter); +void rtl8723a_stop_thread(struct rtw_adapter *padapter); + +s32 c2h_id_filter_ccx_8723a(u8 id); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_led.h b/drivers/staging/rtl8723au/include/rtl8723a_led.h new file mode 100644 index 000000000000..1623d186feb4 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_led.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_LED_H__ +#define __RTL8723A_LED_H__ + +#include +#include + + +/* */ +/* Interface to manipulate LED objects. */ +/* */ +void rtl8723au_InitSwLeds(struct rtw_adapter *padapter); +void rtl8723au_DeInitSwLeds(struct rtw_adapter *padapter); +void SwLedOn23a(struct rtw_adapter *padapter, struct led_8723a * pLed); +void SwLedOff23a(struct rtw_adapter *padapter, struct led_8723a * pLed); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_pg.h b/drivers/staging/rtl8723au/include/rtl8723a_pg.h new file mode 100644 index 000000000000..12f7a1326b4c --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_pg.h @@ -0,0 +1,107 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_PG_H__ +#define __RTL8723A_PG_H__ + +/* */ +/* EEPROM/Efuse PG Offset for 8723E/8723U/8723S */ +/* */ +#define EEPROM_CCK_TX_PWR_INX_8723A 0x10 +#define EEPROM_HT40_1S_TX_PWR_INX_8723A 0x16 +#define EEPROM_HT20_TX_PWR_INX_DIFF_8723A 0x1C +#define EEPROM_OFDM_TX_PWR_INX_DIFF_8723A 0x1F +#define EEPROM_HT40_MAX_PWR_OFFSET_8723A 0x22 +#define EEPROM_HT20_MAX_PWR_OFFSET_8723A 0x25 + +#define EEPROM_ChannelPlan_8723A 0x28 +#define EEPROM_TSSI_A_8723A 0x29 +#define EEPROM_THERMAL_METER_8723A 0x2A +#define RF_OPTION1_8723A 0x2B +#define RF_OPTION2_8723A 0x2C +#define RF_OPTION3_8723A 0x2D +#define RF_OPTION4_8723A 0x2E +#define EEPROM_VERSION_8723A 0x30 +#define EEPROM_CustomID_8723A 0x31 +#define EEPROM_SubCustomID_8723A 0x32 +#define EEPROM_XTAL_K_8723A 0x33 +#define EEPROM_Chipset_8723A 0x34 + +/* RTL8723AE */ +#define EEPROM_VID_8723AE 0x49 +#define EEPROM_DID_8723AE 0x4B +#define EEPROM_SVID_8723AE 0x4D +#define EEPROM_SMID_8723AE 0x4F +#define EEPROM_MAC_ADDR_8723AE 0x67 + +/* RTL8723AU */ +#define EEPROM_MAC_ADDR_8723AU 0xC6 +#define EEPROM_VID_8723AU 0xB7 +#define EEPROM_PID_8723AU 0xB9 + +/* RTL8723AS */ +#define EEPROM_MAC_ADDR_8723AS 0xAA + +/* */ +/* EEPROM/Efuse Value Type */ +/* */ +#define EETYPE_TX_PWR 0x0 + +/* */ +/* EEPROM/Efuse Default Value */ +/* */ +#define EEPROM_Default_CrystalCap_8723A 0x20 + + +/* */ +/* EEPROM/EFUSE data structure definition. */ +/* */ +#define MAX_RF_PATH_NUM 2 +#define MAX_CHNL_GROUP 3+9 + +struct txpowerinfo { + u8 CCKIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 HT40_1SIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 HT40_2SIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 HT20IndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 OFDMIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 HT40MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 HT20MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 TSSI_A[3]; + u8 TSSI_B[3]; + u8 TSSI_A_5G[3]; /* 5GL/5GM/5GH */ + u8 TSSI_B_5G[3]; +}; + +enum bt_ant_num { + Ant_x2 = 0, + Ant_x1 = 1 +}; + +enum bt_cotype { + BT_2Wire = 0, + BT_ISSC_3Wire = 1, + BT_Accel = 2, + BT_CSR_BC4 = 3, + BT_CSR_BC8 = 4, + BT_RTL8756 = 5, + BT_RTL8723A = 6 +}; + +enum bt_radioshared { + BT_Radio_Shared = 0, + BT_Radio_Individual = 1, +}; + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_recv.h b/drivers/staging/rtl8723au/include/rtl8723a_recv.h new file mode 100644 index 000000000000..6bf6904f4d48 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_recv.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_RECV_H__ +#define __RTL8723A_RECV_H__ + +#include +#include + +#define NR_RECVBUFF (4) + +#define NR_PREALLOC_RECV_SKB (8) + +#define RECV_BLK_SZ 512 +#define RECV_BLK_CNT 16 +#define RECV_BLK_TH RECV_BLK_CNT + +#define MAX_RECVBUF_SZ (15360) /* 15k < 16k */ + +#define RECV_BULK_IN_ADDR 0x80 +#define RECV_INT_IN_ADDR 0x81 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 + + +struct phy_stat +{ + unsigned int phydw0; + unsigned int phydw1; + unsigned int phydw2; + unsigned int phydw3; + unsigned int phydw4; + unsigned int phydw5; + unsigned int phydw6; + unsigned int phydw7; +}; + +/* Rx smooth factor */ +#define Rx_Smooth_Factor (20) + +struct interrupt_msg_format { + unsigned int C2H_MSG0; + unsigned int C2H_MSG1; + unsigned int C2H_MSG2; + unsigned int C2H_MSG3; + unsigned int HISR; /* from HISR Reg0x124, read to clear */ + unsigned int HISRE;/* from HISRE Reg0x12c, read to clear */ + unsigned int MSG_EX; +}; + +void rtl8723au_init_recvbuf(struct rtw_adapter *padapter, struct recv_buf *precvbuf); +int rtl8723au_init_recv_priv(struct rtw_adapter * padapter); +void rtl8723au_free_recv_priv(struct rtw_adapter * padapter); +void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe); +void update_recvframe_attrib(struct recv_frame *precvframe, struct recv_stat *prxstat); +void update_recvframe_phyinfo(struct recv_frame *precvframe, struct phy_stat *pphy_info); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_rf.h b/drivers/staging/rtl8723au/include/rtl8723a_rf.h new file mode 100644 index 000000000000..166a45fe47b1 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_rf.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_RF_H__ +#define __RTL8723A_RF_H__ + +/*--------------------------Define Parameters-------------------------------*/ + +/* */ +/* For RF 6052 Series */ +/* */ +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 2 +/*--------------------------Define Parameters-------------------------------*/ + + +/*------------------------------Define structure----------------------------*/ + +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +/*------------------------Export global variable----------------------------*/ + +/*------------------------Export Marco Definition---------------------------*/ + +/*------------------------Export Marco Definition---------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ + +/* */ +/* RF RL6052 Series API */ +/* */ +void rtl8723a_phy_rf6052set_bw(struct rtw_adapter *Adapter, + enum ht_channel_width Bandwidth); +void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter, + u8* pPowerlevel); +void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter, + u8* pPowerLevel, u8 Channel); + +/*--------------------------Exported Function prototype---------------------*/ + +int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_spec.h b/drivers/staging/rtl8723au/include/rtl8723a_spec.h new file mode 100644 index 000000000000..3595c27907d0 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_spec.h @@ -0,0 +1,2158 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + *******************************************************************************/ +#ifndef __RTL8723A_SPEC_H__ +#define __RTL8723A_SPEC_H__ + +/* */ +/* */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* */ +/* */ +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define REG_APS_FSMCO 0x0004 +#define REG_SYS_CLKR 0x0008 +#define REG_9346CR 0x000A +#define REG_EE_VPD 0x000C +#define REG_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_PLL_CTRL 0x0028 +#define REG_MAC_PHY_CTRL 0x002c +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define REG_PWR_DATA 0x0038 +#define REG_CAL_TIMER 0x003C +#define REG_ACLK_MON 0x003E +#define REG_GPIO_MUXCFG 0x0040 +#define REG_GPIO_IO_SEL 0x0042 +#define REG_MAC_PINMUX_CFG 0x0043 +#define REG_GPIO_PIN_CTRL 0x0044 +#define REG_GPIO_INTM 0x0048 +#define REG_LEDCFG0 0x004C +#define REG_LEDCFG1 0x004D +#define REG_LEDCFG2 0x004E +#define REG_LEDCFG3 0x004F +#define REG_LEDCFG REG_LEDCFG2 +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 +#define REG_HSIMR 0x0058 +#define REG_HSISR 0x005c + /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */ +#define REG_GPIO_PIN_CTRL_2 0x0060 + /* RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */ +#define REG_GPIO_IO_SEL_2 0x0062 + /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ +#define REG_MULTI_FUNC_CTRL 0x0068 +#define REG_MCUFWDL 0x0080 +#define REG_HMEBOX_EXT_0 0x0088 +#define REG_HMEBOX_EXT_1 0x008A +#define REG_HMEBOX_EXT_2 0x008C +#define REG_HMEBOX_EXT_3 0x008E + /* Host suspend counter on FPGA platform */ +#define REG_HOST_SUSP_CNT 0x00BC + /* Efuse access protection for RTL8723 */ +#define REG_EFUSE_ACCESS 0x00CF +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_GPIO_OUTSTS 0x00F4 /* For RTL8723 only. */ + +/* */ +/* */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* */ +/* */ +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C +#define REG_HIMR 0x0120 +#define REG_HISR 0x0124 +#define REG_HIMRE 0x0128 +#define REG_HISRE 0x012C +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 + +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015C +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_CLEAR 0x01AF +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_MCUTST_1 0x01c0 +#define REG_FMETHR 0x01C8 +#define REG_HMETFR 0x01CC +#define REG_HMEBOX_0 0x01D0 +#define REG_HMEBOX_1 0x01D4 +#define REG_HMEBOX_2 0x01D8 +#define REG_HMEBOX_3 0x01DC + +#define REG_LLT_INIT 0x01E0 +#define REG_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + + +/* */ +/* */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* */ +/* */ +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +/* */ +/* */ +/* 0x0280h ~ 0x02FFh RXDMA Configuration */ +/* */ +/* */ +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 + + +/* */ +/* */ +/* 0x0300h ~ 0x03FFh PCIe */ +/* */ +/* */ +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 /* Interrupt Migration */ + /* TX Beacon Descriptor Address */ +#define REG_BCNQ_DESA 0x0308 + /* TX High Queue Descriptor Address */ +#define REG_HQ_DESA 0x0310 + /* TX Manage Queue Descriptor Address */ +#define REG_MGQ_DESA 0x0318 + /* TX VO Queue Descriptor Address */ +#define REG_VOQ_DESA 0x0320 + /* TX VI Queue Descriptor Address */ +#define REG_VIQ_DESA 0x0328 + /* TX BE Queue Descriptor Address */ +#define REG_BEQ_DESA 0x0330 + /* TX BK Queue Descriptor Address */ +#define REG_BKQ_DESA 0x0338 + /* RX Queue Descriptor Address */ +#define REG_RX_DESA 0x0340 + /* Backdoor REG for Access Configuration */ +#define REG_DBI 0x0348 + /* MDIO for Access PCIE PHY */ +#define REG_MDIO 0x0354 + /* Debug Selection Register */ +#define REG_DBG_SEL 0x0360 + /* PCIe RPWM */ +#define REG_PCIE_HRPWM 0x0361 + /* PCIe CPWM */ +#define REG_PCIE_HCPWM 0x0363 + /* UART Control */ +#define REG_UART_CTRL 0x0364 + /* UART TX Descriptor Address */ +#define REG_UART_TX_DESA 0x0370 + /* UART Rx Descriptor Address */ +#define REG_UART_RX_DESA 0x0378 + + +/* spec version 11 */ +/* */ +/* */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* */ +/* */ +#define REG_VOQ_INFORMATION 0x0400 +#define REG_VIQ_INFORMATION 0x0404 +#define REG_BEQ_INFORMATION 0x0408 +#define REG_BKQ_INFORMATION 0x040C +#define REG_MGQ_INFORMATION 0x0410 +#define REG_HGQ_INFORMATION 0x0414 +#define REG_BCNQ_INFORMATION 0x0418 + + +#define REG_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_LIFETIME_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044C +#define REG_ARFR3 0x0450 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 + + +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 +#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 +#define REG_STBC_SETTING 0x04C4 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_MAX_AGGR_NUM 0x04CA +#define REG_RTS_MAX_AGGR_NUM 0x04CB +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_DUMMY 0x04FC + + + +/* */ +/* */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* */ +/* */ +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050C +#define REG_BCNTCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS_CCK 0x0514 +#define REG_SIFS_OFDM 0x0516 +#define REG_SIFS_CTX 0x0514 +#define REG_SIFS_TRX 0x0516 +#define REG_TSFTR_SYN_OFFSET 0x0518 +#define REG_AGGR_BREAK_TIME 0x051A +#define REG_SLOT 0x051B +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 +#define REG_BCN_CTRL 0x0550 +#define REG_BCN_CTRL_1 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 + /* The same as REG_MBSSID_BCN_SPACE */ +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 0x0554 +#define REG_DRVERLYINT 0x0558 +#define REG_BCNDMATIM 0x0559 +#define REG_ATIMWND 0x055A +#define REG_BCN_MAX_ERR 0x055D +#define REG_RXTSF_OFFSET_CCK 0x055E +#define REG_RXTSF_OFFSET_OFDM 0x055F +#define REG_TSFTR 0x0560 +#define REG_TSFTR1 0x0568 +#define REG_INIT_TSFTR 0x0564 +#define REG_ATIMWND_1 0x0570 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_SCH_TXCMD 0x05D0 + +/* define REG_FW_TSF_SYNC_CNT 0x04A0 */ +#define REG_FW_RESET_TSF_CNT_1 0x05FC +#define REG_FW_RESET_TSF_CNT_0 0x05FD +#define REG_FW_BCN_DIS_CNT 0x05FE + +/* */ +/* */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* */ +/* */ +#define REG_APSD_CTRL 0x0600 +#define REG_BWOPMODE 0x0603 +#define REG_TCR 0x0604 +#define REG_RCR 0x0608 +#define REG_RX_PKT_LIMIT 0x060C +#define REG_RX_DLK_TIME 0x060D +#define REG_RX_DRVINFO_SZ 0x060F + +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG 0x0628 + +#define REG_USTIME_EDCA 0x0638 +#define REG_MAC_SPEC_SIFS 0x063A + +/* 20100719 Joseph: Hardware register definition change. (HW datasheet v54) */ + /* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */ +#define REG_R2T_SIFS 0x063C + /* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */ +#define REG_T2T_SIFS 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +/* WMA, BA, CCX */ +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 + + +/* Security */ +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +/* Power */ +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_CMD 0x0698 +#define REG_WKFMCAM_RWD 0x069C +#define REG_RXFLTMAP0 0x06A0 +#define REG_RXFLTMAP1 0x06A2 +#define REG_RXFLTMAP2 0x06A4 +#define REG_BCN_PSR_RPT 0x06A8 +#define REG_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + +#define REG_MACID1 0x0700 +#define REG_BSSID1 0x0708 + + +/* */ +/* */ +/* 0xFE00h ~ 0xFE55h USB Configuration */ +/* */ +/* */ +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +/* For test chip */ +#define REG_TEST_USB_TXQS 0xFE48 +#define REG_TEST_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */ +#define REG_TEST_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */ +#define REG_TEST_SIE_OPTIONAL 0xFE64 +#define REG_TEST_SIE_CHIRP_K 0xFE65 +#define REG_TEST_SIE_PHY 0xFE66 /* 0xFE66~0xFE6B */ +#define REG_TEST_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ +#define REG_TEST_SIE_STRING 0xFE80 /* 0xFE80~0xFEB9 */ + + +/* For normal chip */ +#define REG_NORMAL_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */ +#define REG_NORMAL_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */ +#define REG_NORMAL_SIE_OPTIONAL 0xFE64 +#define REG_NORMAL_SIE_EP 0xFE65 /* 0xFE65~0xFE67 */ +#define REG_NORMAL_SIE_PHY 0xFE68 /* 0xFE68~0xFE6B */ +#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C +#define REG_NORMAL_SIE_GPS_EP 0xFE6D /* RTL8723 only */ +#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ +#define REG_NORMAL_SIE_STRING 0xFE80 /* 0xFE80~0xFEDF */ + + +/* */ +/* */ +/* Redifine 8192C register definition for compatibility */ +/* */ +/* */ + +/* TODO: use these definition when using REG_xxx naming rule. */ +/* NOTE: DO NOT Remove these definition. Use later. */ + + /* System Isolation Interface Control. */ +#define SYS_ISO_CTRL REG_SYS_ISO_CTRL + /* System Function Enable. */ +#define SYS_FUNC_EN REG_SYS_FUNC_EN +#define SYS_CLK REG_SYS_CLKR + /* 93C46/93C56 Command Register. */ +#define CR9346 REG_9346CR + /* E-Fuse Control. */ +#define EFUSE_CTRL REG_EFUSE_CTRL + /* E-Fuse Test. */ +#define EFUSE_TEST REG_EFUSE_TEST + /* Media Status register */ +#define MSR (REG_CR + 2) +#define ISR REG_HISR + /* Timing Sync Function Timer Register. */ +#define TSFR REG_TSFTR + + /* MAC ID Register, Offset 0x0050-0x0053 */ +#define MACIDR0 REG_MACID + /* MAC ID Register, Offset 0x0054-0x0055 */ +#define MACIDR4 (REG_MACID + 4) + +#define PBP REG_PBP + + /* Redifine MACID register, to compatible prior ICs. */ +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + + +/* */ +/* 9. Security Control Registers (Offset: ) */ +/* */ + /* IN 8190 Data Sheet is called CAMcmd */ +#define RWCAM REG_CAMCMD + /* Software write CAM input content */ +#define WCAMI REG_CAMWRITE + /* Software read/write CAM config */ +#define RCAMO REG_CAMREAD +#define CAMDBG REG_CAMDBG + /* Security Configuration Register */ +#define SECR REG_SECCFG + +/* Unused register */ +#define UnusedRegister 0x1BF +#define DCAM UnusedRegister +#define PSR UnusedRegister +#define BBAddr UnusedRegister +#define PhyDataR UnusedRegister + +#define InvalidBBRFValue 0x12345678 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +/* */ +/* 8192C Cmd9346CR bits (Offset 0xA, 16bit) */ +/* */ + /* EEPROM enable when set 1 */ +#define CmdEEPROM_En BIT5 + /* System EEPROM select, 0: boot from E-FUSE, + 1: The EEPROM used is 9346 */ +#define CmdEERPOMSEL BIT4 +#define Cmd9346CR_9356SEL BIT4 +#define AutoLoadEEPROM (CmdEEPROM_En|CmdEERPOMSEL) +#define AutoLoadEFUSE CmdEEPROM_En + +/* */ +/* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */ +/* */ +#define GPIOSEL_GPIO 0 +#define GPIOSEL_ENBT BIT5 + +/* */ +/* 8192C GPIO PIN Control Register (offset 0x44, 4 byte) */ +/* */ + /* GPIO pins input value */ +#define GPIO_IN REG_GPIO_PIN_CTRL + /* GPIO pins output value */ +#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) + /* GPIO pins output enable when a bit is set to "1"; + otherwise, input is configured. */ +#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) +#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) + +/* */ +/* 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) */ +/* */ +/* +Network Type +00: No link +01: Link in ad hoc network +10: Link in infrastructure network +11: AP mode +Default: 00b. +*/ +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +/* */ +/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */ +/* */ +/* */ +/* 8192C Response Rate Set Register (offset 0x181, 24bits) */ +/* */ +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_AckShortPmb BIT23 +/* CCK ACK: use Short Preamble or not */ + +/* */ +/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */ +/* */ +#define BW_OPMODE_20MHZ BIT2 +#define BW_OPMODE_5G BIT1 +#define BW_OPMODE_11J BIT0 + + +/* */ +/* 8192C CAM Config Setting (offset 0x250, 1 byte) */ +/* */ +#define CAM_VALID BIT15 +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT5 + +#define CAM_CONTENT_COUNT 8 + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_CONFIG_USEDK true +#define CAM_CONFIG_NO_USEDK false + +#define CAM_WRITE BIT16 +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT31 + +#define SCR_UseDK 0x01 +#define SCR_TxSecEnable 0x02 +#define SCR_RxSecEnable 0x04 + + +/* */ +/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */ +/* */ +/* */ +/* 8190 IMR/ISR bits (offset 0xfd, 8bits) */ +/* */ +#define IMR8190_DISABLED 0x0 +/* IMR DW0 Bit 0-31 */ + +#define IMR_BCNDMAINT6 BIT31 /* Beacon DMA Interrupt 6 */ +#define IMR_BCNDMAINT5 BIT30 /* Beacon DMA Interrupt 5 */ +#define IMR_BCNDMAINT4 BIT29 /* Beacon DMA Interrupt 4 */ +#define IMR_BCNDMAINT3 BIT28 /* Beacon DMA Interrupt 3 */ +#define IMR_BCNDMAINT2 BIT27 /* Beacon DMA Interrupt 2 */ +#define IMR_BCNDMAINT1 BIT26 /* Beacon DMA Interrupt 1 */ +#define IMR_BCNDOK8 BIT25 /* Beacon Queue DMA OK + Interrupt 8 */ +#define IMR_BCNDOK7 BIT24 /* Beacon Queue DMA OK + Interrupt 7 */ +#define IMR_BCNDOK6 BIT23 /* Beacon Queue DMA OK + Interrupt 6 */ +#define IMR_BCNDOK5 BIT22 /* Beacon Queue DMA OK + Interrupt 5 */ +#define IMR_BCNDOK4 BIT21 /* Beacon Queue DMA OK + Interrupt 4 */ +#define IMR_BCNDOK3 BIT20 /* Beacon Queue DMA OK + Interrupt 3 */ +#define IMR_BCNDOK2 BIT19 /* Beacon Queue DMA OK + Interrupt 2 */ +#define IMR_BCNDOK1 BIT18 /* Beacon Queue DMA OK + Interrupt 1 */ +#define IMR_TIMEOUT2 BIT17 /* Timeout interrupt 2 */ +#define IMR_TIMEOUT1 BIT16 /* Timeout interrupt 1 */ +#define IMR_TXFOVW BIT15 /* Transmit FIFO Overflow */ +#define IMR_PSTIMEOUT BIT14 /* Power save time out + interrupt */ +#define IMR_BcnInt BIT13 /* Beacon DMA Interrupt 0 */ +#define IMR_RXFOVW BIT12 /* Receive FIFO Overflow */ +#define IMR_RDU BIT11 /* Receive Descriptor + Unavailable */ +#define IMR_ATIMEND BIT10 /* For 92C,ATIM Window + End Interrupt */ +#define IMR_BDOK BIT9 /* Beacon Queue DMA OK + Interrup */ +#define IMR_HIGHDOK BIT8 /* High Queue DMA OK + Interrupt */ +#define IMR_TBDOK BIT7 /* Transmit Beacon OK + interrup */ +#define IMR_MGNTDOK BIT6 /* Management Queue DMA OK + Interrupt */ +#define IMR_TBDER BIT5 /* For 92C,Transmit Beacon + Error Interrupt */ +#define IMR_BKDOK BIT4 /* AC_BK DMA OK Interrupt */ +#define IMR_BEDOK BIT3 /* AC_BE DMA OK Interrupt */ +#define IMR_VIDOK BIT2 /* AC_VI DMA OK Interrupt */ +#define IMR_VODOK BIT1 /* AC_VO DMA Interrupt */ +#define IMR_ROK BIT0 /* Receive DMA OK Interrupt */ + +#define IMR_RX_MASK (IMR_ROK|IMR_RDU|IMR_RXFOVW) +#define IMR_TX_MASK (IMR_VODOK|IMR_VIDOK|IMR_BEDOK| \ + IMR_BKDOK|IMR_MGNTDOK|IMR_HIGHDOK| \ + IMR_BDOK) + +/* 13. Host Interrupt Status Extension Register (Offset: 0x012C-012Eh) */ +#define IMR_BcnInt_E BIT12 +#define IMR_TXERR BIT11 +#define IMR_RXERR BIT10 +#define IMR_C2HCMD BIT9 +#define IMR_CPWM BIT8 +/* RSVD [2-7] */ +#define IMR_OCPINT BIT1 +#define IMR_WLANOFF BIT0 + + +/* 8192C EEPROM/EFUSE share register definition. */ + +/* Default Value for EEPROM or EFUSE!!! */ +#define EEPROM_Default_TSSI 0x0 +#define EEPROM_Default_TxPowerDiff 0x0 +#define EEPROM_Default_CrystalCap 0x5 + /* Default: 2X2, RTL8192CE(QFPN68) */ +#define EEPROM_Default_BoardType 0x02 +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_Default_HT2T_TxPwr 0x10 + +#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 +#define EEPROM_Default_ThermalMeter 0x12 + +#define EEPROM_Default_AntTxPowerDiff 0x0 +#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 +#define EEPROM_Default_TxPowerLevel 0x22 +#define EEPROM_Default_HT40_2SDiff 0x0 + /* HT20<->40 default Tx Power Index Difference */ +#define EEPROM_Default_HT20_Diff 2 +#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 +#define EEPROM_Default_HT40_PwrMaxOffset 0 +#define EEPROM_Default_HT20_PwrMaxOffset 0 + +/* For debug */ +#define EEPROM_Default_PID 0x1234 +#define EEPROM_Default_VID 0x5678 +#define EEPROM_Default_CustomerID 0xAB +#define EEPROM_Default_SubCustomerID 0xCD +#define EEPROM_Default_Version 0 + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_USB_OPTIONAL1 0xE +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_TOSHIBA 0x4 + /* CCX test. By Bruce, 2009-02-25. */ +#define EEPROM_CID_CCX 0x10 +#define EEPROM_CID_QMI 0x0D + /* added by chiyoko for dtm, 20090108 */ +#define EEPROM_CID_WHQL 0xFE + + +#define RTL_EEPROM_ID 0x8129 + +#define SUPPORT_HW_RADIO_DETECT(pHalData) \ + (pHalData->BoardType == BOARD_MINICARD || \ + pHalData->BoardType == BOARD_USB_SOLO || \ + pHalData->BoardType == BOARD_USB_COMBO) + +/* */ +/* EEPROM address for Test chip */ +/* */ +#define EEPROM_TEST_USB_OPT 0x0E +#define EEPROM_TEST_CHIRP_K 0x0F +#define EEPROM_TEST_EP_SETTING 0x0E +#define EEPROM_TEST_USB_PHY 0x10 + + +/* */ +/* EEPROM address for Normal chip */ +/* */ +#define EEPROM_NORMAL_USB_OPT 0x0E +#define EEPROM_NORMAL_CHIRP_K 0x0E /* Changed */ +#define EEPROM_NORMAL_EP_SETTING 0x0F /* Changed */ +#define EEPROM_NORMAL_USB_PHY 0x12 /* Changed */ + +enum { + BOARD_USB_DONGLE = 0, /* USB dongle */ + BOARD_USB_High_PA = 1, /* USB dongle with high power PA */ + BOARD_MINICARD = 2, /* Minicard */ + BOARD_USB_SOLO = 3, /* USB solo-Slim module */ + BOARD_USB_COMBO = 4, /* USB Combo-Slim module */ +}; + +/* Test chip and normal chip common define */ +/* */ +/* EEPROM address for both */ +/* */ +#define EEPROM_ID0 0x00 +#define EEPROM_ID1 0x01 +#define EEPROM_RTK_RSV1 0x02 +#define EEPROM_RTK_RSV2 0x03 +#define EEPROM_RTK_RSV3 0x04 +#define EEPROM_RTK_RSV4 0x05 +#define EEPROM_RTK_RSV5 0x06 +#define EEPROM_DBG_SEL 0x07 +#define EEPROM_RTK_RSV6 0x08 +#define EEPROM_VID 0x0A +#define EEPROM_PID 0x0C + +#define EEPROM_MAC_ADDR 0x16 +#define EEPROM_STRING 0x1C +#define EEPROM_SUBCUSTOMER_ID 0x59 +#define EEPROM_CCK_TX_PWR_INX 0x5A +#define EEPROM_HT40_1S_TX_PWR_INX 0x60 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66 +#define EEPROM_HT20_TX_PWR_INX_DIFF 0x69 +#define EEPROM_OFDM_TX_PWR_INX_DIFF 0x6C +#define EEPROM_HT40_MAX_PWR_OFFSET 0x6F +#define EEPROM_HT20_MAX_PWR_OFFSET 0x72 + +#define EEPROM_CHANNEL_PLAN 0x75 +#define EEPROM_TSSI_A 0x76 +#define EEPROM_TSSI_B 0x77 +#define EEPROM_THERMAL_METER 0x78 +#define EEPROM_RF_OPT1 0x79 +#define EEPROM_RF_OPT2 0x7A +#define EEPROM_RF_OPT3 0x7B +#define EEPROM_RF_OPT4 0x7C +#define EEPROM_VERSION 0x7E +#define EEPROM_CUSTOMER_ID 0x7F + + /* 0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU */ +#define EEPROM_BoardType 0x54 + /* 0x5C-0x76, Tx Power index. */ +#define EEPROM_TxPwIndex 0x5C + /* Difference of gain index between legacy and high throughput OFDM. */ +#define EEPROM_PwDiff 0x67 + /* CCK Tx Power */ +#define EEPROM_TxPowerCCK 0x5A + +/* 2009/02/09 Cosa Add for SD3 requirement */ + /* HT20 Tx Power Index Difference */ +#define EEPROM_TX_PWR_HT20_DIFF 0x6e + /* HT20<->40 default Tx Power Index Difference */ +#define DEFAULT_HT20_TXPWR_DIFF 2 + /* OFDM Tx Power Index Difference */ +#define EEPROM_TX_PWR_OFDM_DIFF 0x71 + + /* Power diff for channel group */ +#define EEPROM_TxPWRGroup 0x73 + /* Check if power safety is need */ +#define EEPROM_Regulatory 0x79 + + /* 92cu, 0x7E[4] */ +#define EEPROM_BLUETOOTH_COEXIST 0x7E +#define EEPROM_NORMAL_BoardType EEPROM_RF_OPT1 /* 7:5] */ +#define BOARD_TYPE_NORMAL_MASK 0xE0 +#define BOARD_TYPE_TEST_MASK 0x0F + /* BIT0 1 for build-in module, 0 for external dongle */ +#define EEPROM_EASY_REPLACEMENT 0x50 +/* */ +/* EPROM content definitions */ +/* */ +#define OS_LINK_SPEED BIT(5) + +#define BOARD_TYPE_MASK 0xF + +#define BT_COEXISTENCE BIT(4) +#define BT_CO_SHIFT 4 + +#define EP_NUMBER_MASK 0x30 /* bit 4:5 0Eh */ +#define EP_NUMBER_SHIFT 4 + + +#define USB_PHY_PARA_SIZE 5 + + +/* */ +/* EEPROM default value definitions */ +/* */ +/* Use 0xABCD instead of 0x8192 for debug */ +#define EEPROM_DEF_ID_0 0xCD /* Byte 0x00 */ +#define EEPROM_DEF_ID_1 0xAB /* Byte 0x01 */ + +#define EEPROM_DEF_RTK_RSV_A3 0x74 /* Byte 0x03 */ +#define EEPROM_DEF_RTK_RSV_A4 0x6D /* Byte 0x04 */ +#define EEPROM_DEF_RTK_RSV_A8 0xFF /* Byte 0x08 */ + +#define EEPROM_DEF_VID_0 0x0A /* Byte 0x0A */ +#define EEPROM_DEF_VID_1 0x0B + +#define EEPROM_DEF_PID_0 0x92 /* Byte 0x0C */ +#define EEPROM_DEF_PID_1 0x81 + + +#define EEPROM_TEST_DEF_USB_OPT 0x80 /* Byte 0x0E */ +#define EEPROM_NORMAL_DEF_USB_OPT 0x00 /* Byte 0x0E */ + +#define EEPROM_DEF_CHIRPK 0x15 /* Byte 0x0F */ + +#define EEPROM_DEF_USB_PHY_0 0x85 /* Byte 0x10 */ +#define EEPROM_DEF_USB_PHY_1 0x62 /* Byte 0x11 */ +#define EEPROM_DEF_USB_PHY_2 0x9E /* Byte 0x12 */ +#define EEPROM_DEF_USB_PHY_3 0x06 /* Byte 0x13 */ + +#define EEPROM_DEF_TSSI_A 0x09 /* Byte 0x78 */ +#define EEPROM_DEF_TSSI_B 0x09 /* Byte 0x79 */ + + +#define EEPROM_DEF_THERMAL_METER 0x12 /* Byte 0x7A */ + + /* Check if power safety spec is need */ +#define RF_OPTION1 0x79 +#define RF_OPTION2 0x7A +#define RF_OPTION3 0x7B +#define RF_OPTION4 0x7C + + +#define EEPROM_USB_SN BIT(0) +#define EEPROM_USB_REMOTE_WAKEUP BIT(1) +#define EEPROM_USB_DEVICE_PWR BIT(2) +#define EEPROM_EP_NUMBER (BIT(3)|BIT(4)) + +/*=================================================================== +===================================================================== +Here the register defines are for 92C. When the define is as same with 92C, +we will use the 92C's define for the consistency +So the following defines for 92C is not entire!!!!!! +===================================================================== +=====================================================================*/ +/* +Based on Datasheet V33---090401 +Register Summary +Current IOREG MAP +0x0000h ~ 0x00FFh System Configuration (256 Bytes) +0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) +0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) +0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) +0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) +0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) +0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) +0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) +0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) +*/ + +/* */ +/* 8192C (RCR) Receive Configuration Register (Offset 0x608, 32 bits) */ +/* */ +#define RCR_APPFCS BIT31 /* WMAC append FCS after payload*/ +#define RCR_APP_MIC BIT30 +#define RCR_APP_PHYSTS BIT28 +#define RCR_APP_ICV BIT29 +#define RCR_APP_PHYST_RXFF BIT28 +#define RCR_APP_BA_SSN BIT27 /* Accept BA SSN */ +#define RCR_ENMBID BIT24 /* Enable Multiple BssId. */ +#define RCR_LSIGEN BIT23 +#define RCR_MFBEN BIT22 +#define RCR_HTC_LOC_CTRL BIT14 /* MFC<--HTC=1 MFC-->HTC=0 */ +#define RCR_AMF BIT13 /* Accept management type frame */ +#define RCR_ACF BIT12 /* Accept control type frame */ +#define RCR_ADF BIT11 /* Accept data type frame */ +#define RCR_AICV BIT9 /* Accept ICV error packet */ +#define RCR_ACRC32 BIT8 /* Accept CRC32 error packet */ +#define RCR_CBSSID_BCN BIT7 /* Accept BSSID match packet + (Rx beacon, probe rsp) */ +#define RCR_CBSSID_DATA BIT6 /* Accept BSSID match packet + (Data) */ +#define RCR_CBSSID RCR_CBSSID_DATA /* Accept BSSID match + packet */ +#define RCR_APWRMGT BIT5 /* Accept power management + packet */ +#define RCR_ADD3 BIT4 /* Accept address 3 match + packet */ +#define RCR_AB BIT3 /* Accept broadcast packet */ +#define RCR_AM BIT2 /* Accept multicast packet */ +#define RCR_APM BIT1 /* Accept physical match packet */ +#define RCR_AAP BIT0 /* Accept all unicast packet */ +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + + + +/* */ +/* 8192c USB specific Regsiter Offset and Content definition, */ +/* 2009.08.18, added by vivi. for merge 92c and 92C into one driver */ +/* */ +/* define APS_FSMCO 0x0004 same with 92Ce */ +#define RSV_CTRL 0x001C +#define RD_CTRL 0x0524 + +/* */ +/* */ +/* 0xFE00h ~ 0xFE55h USB Configuration */ +/* */ +/* */ +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_USB_VID 0xFE60 +#define REG_USB_PID 0xFE62 +#define REG_USB_OPTIONAL 0xFE64 +#define REG_USB_CHIRP_K 0xFE65 +#define REG_USB_PHY 0xFE66 +#define REG_USB_MAC_ADDR 0xFE70 + +#define REG_USB_HRPWM 0xFE58 +#define REG_USB_HCPWM 0xFE57 + +#define InvalidBBRFValue 0x12345678 + +/* */ +/* 8192C Regsiter Bit and Content definition */ +/* */ +/* */ +/* */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* */ +/* */ + +/* 2 SPS0_CTRL */ +#define SW18_FPWM BIT(3) + + +/* 2 SYS_ISO_CTRL */ +#define ISO_MD2PP BIT(0) +#define ISO_UA2USB BIT(1) +#define ISO_UD2CORE BIT(2) +#define ISO_PA2PCIE BIT(3) +#define ISO_PD2CORE BIT(4) +#define ISO_IP2MAC BIT(5) +#define ISO_DIOP BIT(6) +#define ISO_DIOE BIT(7) +#define ISO_EB2CORE BIT(8) +#define ISO_DIOR BIT(9) + +#define PWC_EV25V BIT(14) +#define PWC_EV12V BIT(15) + + +/* 2 SYS_FUNC_EN */ +#define FEN_BBRSTB BIT(0) +#define FEN_BB_GLB_RSTn BIT(1) +#define FEN_USBA BIT(2) +#define FEN_UPLL BIT(3) +#define FEN_USBD BIT(4) +#define FEN_DIO_PCIE BIT(5) +#define FEN_PCIEA BIT(6) +#define FEN_PPLL BIT(7) +#define FEN_PCIED BIT(8) +#define FEN_DIOE BIT(9) +#define FEN_CPUEN BIT(10) +#define FEN_DCORE BIT(11) +#define FEN_ELDR BIT(12) +#define FEN_DIO_RF BIT(13) +#define FEN_HWPDN BIT(14) +#define FEN_MREGEN BIT(15) + +/* 2 APS_FSMCO */ +#define PFM_LDALL BIT(0) +#define PFM_ALDN BIT(1) +#define PFM_LDKP BIT(2) +#define PFM_WOWL BIT(3) +#define EnPDN BIT(4) +#define PDN_PL BIT(5) +#define APFM_ONMAC BIT(8) +#define APFM_OFF BIT(9) +#define APFM_RSM BIT(10) +#define AFSM_HSUS BIT(11) +#define AFSM_PCIE BIT(12) +#define APDM_MAC BIT(13) +#define APDM_HOST BIT(14) +#define APDM_HPDN BIT(15) +#define RDY_MACON BIT(16) +#define SUS_HOST BIT(17) +#define ROP_ALD BIT(20) +#define ROP_PWR BIT(21) +#define ROP_SPS BIT(22) +#define SOP_MRST BIT(25) +#define SOP_FUSE BIT(26) +#define SOP_ABG BIT(27) +#define SOP_AMB BIT(28) +#define SOP_RCK BIT(29) +#define SOP_A8M BIT(30) +#define XOP_BTCK BIT(31) + +/* 2 SYS_CLKR */ +#define ANAD16V_EN BIT(0) +#define ANA8M BIT(1) +#define MACSLP BIT(4) +#define LOADER_CLK_EN BIT(5) +#define _80M_SSC_DIS BIT(7) +#define _80M_SSC_EN_HO BIT(8) +#define PHY_SSC_RSTB BIT(9) +#define SEC_CLK_EN BIT(10) +#define MAC_CLK_EN BIT(11) +#define SYS_CLK_EN BIT(12) +#define RING_CLK_EN BIT(13) + + +/* 2 9346CR */ + + +#define EEDO BIT(0) +#define EEDI BIT(1) +#define EESK BIT(2) +#define EECS BIT(3) +/* define EERPROMSEL BIT(4) */ +/* define EEPROM_EN BIT(5) */ +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) +#define EEM0 BIT(6) +#define EEM1 BIT(7) + + +/* 2 AFE_MISC */ +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + + +/* 2 SPS0_CTRL */ + + +/* 2 SPS_OCP_CFG */ + + +/* 2 RSV_CTRL */ +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define R_DIS_PRST_0 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +/* 2 RF_CTRL */ +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + + + +/* 2 LDOA15_CTRL */ +#define LDA15_EN BIT(0) +#define LDA15_STBY BIT(1) +#define LDA15_OBUF BIT(2) +#define LDA15_REG_VOS BIT(3) +#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) + + + +/* 2 LDOV12D_CTRL */ +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) +#define _LDV12_VADJ(x) (((x) & 0xF) << 4) + + +/* 2 AFE_XTAL_CTRL */ +#define XTAL_EN BIT(0) +#define XTAL_BSEL BIT(1) +#define _XTAL_BOSC(x) (((x) & 0x3) << 2) +#define _XTAL_CADJ(x) (((x) & 0xF) << 4) +#define XTAL_GATE_USB BIT(8) +#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) +#define XTAL_GATE_AFE BIT(11) +#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) +#define XTAL_RF_GATE BIT(14) +#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) +#define XTAL_GATE_DIG BIT(17) +#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) +#define XTAL_BT_GATE BIT(20) +#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) +#define _XTAL_GPIO(x) (((x) & 0x7) << 23) + + +#define CKDLY_AFE BIT(26) +#define CKDLY_USB BIT(27) +#define CKDLY_DIG BIT(28) +#define CKDLY_BT BIT(29) + + +/* 2 AFE_PLL_CTRL */ +#define APLL_EN BIT(0) +#define APLL_320_EN BIT(1) +#define APLL_FREF_SEL BIT(2) +#define APLL_EDGE_SEL BIT(3) +#define APLL_WDOGB BIT(4) +#define APLL_LPFEN BIT(5) + +#define APLL_REF_CLK_13MHZ 0x1 +#define APLL_REF_CLK_19_2MHZ 0x2 +#define APLL_REF_CLK_20MHZ 0x3 +#define APLL_REF_CLK_25MHZ 0x4 +#define APLL_REF_CLK_26MHZ 0x5 +#define APLL_REF_CLK_38_4MHZ 0x6 +#define APLL_REF_CLK_40MHZ 0x7 + +#define APLL_320EN BIT(14) +#define APLL_80EN BIT(15) +#define APLL_1MEN BIT(24) + + +/* 2 EFUSE_CTRL */ +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +/* 2 EFUSE_TEST (For RTL8723 partially) */ +#define EF_TRPT BIT(7) + /* 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */ +#define EF_CELL_SEL (BIT(8)|BIT(9)) +#define LDOE25_EN BIT(31) +#define EFUSE_SEL(x) (((x) & 0x3) << 8) +#define EFUSE_SEL_MASK 0x300 +#define EFUSE_WIFI_SEL_0 0x0 +#define EFUSE_BT_SEL_0 0x1 +#define EFUSE_BT_SEL_1 0x2 +#define EFUSE_BT_SEL_2 0x3 + +#define EFUSE_ACCESS_ON 0x69 /* For RTL8723 only. */ +#define EFUSE_ACCESS_OFF 0x00 /* For RTL8723 only. */ + +/* 2 PWR_DATA */ + +/* 2 CAL_TIMER */ + +/* 2 ACLK_MON */ +#define RSM_EN BIT(0) +#define Timer_EN BIT(4) + + +/* 2 GPIO_MUXCFG */ +#define TRSW0EN BIT(2) +#define TRSW1EN BIT(3) +#define EROM_EN BIT(4) +#define EnBT BIT(5) +#define EnUart BIT(8) +#define Uart_910 BIT(9) +#define EnPMAC BIT(10) +#define SIC_SWRST BIT(11) +#define EnSIC BIT(12) +#define SIC_23 BIT(13) +#define EnHDP BIT(14) +#define SIC_LBK BIT(15) + +/* 2 GPIO_PIN_CTRL */ + +/* GPIO BIT */ +#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) + +/* 2 GPIO_INTM */ + +/* 2 LEDCFG */ +#define LED0PL BIT(4) +#define LED0DIS BIT(7) +#define LED1DIS BIT(15) +#define LED1PL BIT(12) + +#define SECCAM_CLR BIT(30) + + +/* 2 FSIMR */ + +/* 2 FSISR */ + + +/* 2 8051FWDL */ +/* 2 MCUFWDL */ +#define MCUFWDL_EN BIT(0) +#define MCUFWDL_RDY BIT(1) +#define FWDL_ChkSum_rpt BIT(2) +#define MACINI_RDY BIT(3) +#define BBINI_RDY BIT(4) +#define RFINI_RDY BIT(5) +#define WINTINI_RDY BIT(6) +#define CPRST BIT(23) + +/* 2REG_HPON_FSM */ +#define BOND92CE_1T2R_CFG BIT(22) + + +/* 2 REG_SYS_CFG */ +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15)) +#define BT_FUNC BIT(16) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define CHIP_VER_RTL_MASK 0xF000 /* Bit 12 ~ 15 */ +#define CHIP_VER_RTL_SHIFT 12 + +/* 2REG_GPIO_OUTSTS (For RTL8723 only) */ +#define EFS_HCI_SEL (BIT(0)|BIT(1)) +#define PAD_HCI_SEL (BIT(2)|BIT(3)) +#define HCI_SEL (BIT(4)|BIT(5)) +#define PKG_SEL_HCI BIT(6) +#define FEN_GPS BIT(7) +#define FEN_BT BIT(8) +#define FEN_WL BIT(9) +#define FEN_PCI BIT(10) +#define FEN_USB BIT(11) +#define BTRF_HWPDN_N BIT(12) +#define WLRF_HWPDN_N BIT(13) +#define PDN_BT_N BIT(14) +#define PDN_GPS_N BIT(15) +#define BT_CTL_HWPDN BIT(16) +#define GPS_CTL_HWPDN BIT(17) +#define PPHY_SUSB BIT(20) +#define UPHY_SUSB BIT(21) +#define PCI_SUSEN BIT(22) +#define USB_SUSEN BIT(23) +#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) + +/* */ +/* */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* */ +/* */ + + +/* 2 Function Enable Registers */ +/* 2 CR */ + +#define REG_LBMODE (REG_CR + 3) + + +#define HCI_TXDMA_EN BIT(0) +#define HCI_RXDMA_EN BIT(1) +#define TXDMA_EN BIT(2) +#define RXDMA_EN BIT(3) +#define PROTOCOL_EN BIT(4) +#define SCHEDULE_EN BIT(5) +#define MACTXEN BIT(6) +#define MACRXEN BIT(7) +#define ENSWBCN BIT(8) +#define ENSEC BIT(9) + +/* Network type */ +#define _NETTYPE(x) (((x) & 0x3) << 16) +#define MASK_NETTYPE 0x30000 +#define NT_NO_LINK 0x0 +#define NT_LINK_AD_HOC 0x1 +#define NT_LINK_AP 0x2 +#define NT_AS_AP 0x3 + +#define _LBMODE(x) (((x) & 0xF) << 24) +#define MASK_LBMODE 0xF000000 +#define LOOPBACK_NORMAL 0x0 +#define LOOPBACK_IMMEDIATELY 0xB +#define LOOPBACK_MAC_DELAY 0x3 +#define LOOPBACK_PHY 0x1 +#define LOOPBACK_DMA 0x7 + + +/* 2 PBP - Page Size Register */ +#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) +#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) +#define _PSRX_MASK 0xF +#define _PSTX_MASK 0xF0 +#define _PSRX(x) (x) +#define _PSTX(x) ((x) << 4) + +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + + +/* 2 TX/RXDMA */ +#define RXDMA_ARBBW_EN BIT(0) +#define RXSHFT_EN BIT(1) +#define RXDMA_AGG_EN BIT(2) +#define QS_VO_QUEUE BIT(8) +#define QS_VI_QUEUE BIT(9) +#define QS_BE_QUEUE BIT(10) +#define QS_BK_QUEUE BIT(11) +#define QS_MANAGER_QUEUE BIT(12) +#define QS_HIGH_QUEUE BIT(13) + +#define HQSEL_VOQ BIT(0) +#define HQSEL_VIQ BIT(1) +#define HQSEL_BEQ BIT(2) +#define HQSEL_BKQ BIT(3) +#define HQSEL_MGTQ BIT(4) +#define HQSEL_HIQ BIT(5) + +/* For normal driver, 0x10C */ +#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) +#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) +#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) + +#define QUEUE_LOW 1 +#define QUEUE_NORMAL 2 +#define QUEUE_HIGH 3 + + + +/* 2 TRXFF_BNDY */ + + +/* 2 LLT_INIT */ +#define _LLT_NO_ACTIVE 0x0 +#define _LLT_WRITE_ACCESS 0x1 +#define _LLT_READ_ACCESS 0x2 + +#define _LLT_INIT_DATA(x) ((x) & 0xFF) +#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) +#define _LLT_OP(x) (((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) + + +/* 2 BB_ACCESS_CTRL */ +#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) +#define BB_WRITE_EN BIT(30) +#define BB_READ_EN BIT(31) +/* define BB_ADDR_MASK 0xFFF */ +/* define _BB_ADDR(x) ((x) & BB_ADDR_MASK) */ + +/* */ +/* */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* */ +/* */ +/* 2 RQPN */ +#define _HPQ(x) ((x) & 0xFF) +#define _LPQ(x) (((x) & 0xFF) << 8) +#define _PUBQ(x) (((x) & 0xFF) << 16) + /* NOTE: in RQPN_NPQ register */ +#define _NPQ(x) ((x) & 0xFF) + + +#define HPQ_PUBLIC_DIS BIT(24) +#define LPQ_PUBLIC_DIS BIT(25) +#define LD_RQPN BIT(31) + + +/* 2 TDECTRL */ +#define BCN_VALID BIT(16) +#define BCN_HEAD(x) (((x) & 0xFF) << 8) +#define BCN_HEAD_MASK 0xFF00 + +/* 2 TDECTL */ +#define BLK_DESC_NUM_SHIFT 4 +#define BLK_DESC_NUM_MASK 0xF + + +/* 2 TXDMA_OFFSET_CHK */ +#define DROP_DATA_EN BIT(9) + +/* */ +/* */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* */ +/* */ +/* 2 FWHW_TXQ_CTRL */ +#define EN_AMPDU_RTY_NEW BIT(7) + +/* 2 INIRTSMCS_SEL */ +#define _INIRTSMCS_SEL(x) ((x) & 0x3F) + + +/* 2 SPEC SIFS */ +#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) + + +/* 2 RRSR */ + +#define RATE_REG_BITMAP_ALL 0xFFFFF + +#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) + +#define _RRSR_RSC(x) (((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED 0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 +#define RRSR_RSC_DUPLICATE_MODE 0x3 + + +/* 2 ARFR */ +#define USE_SHORT_G1 BIT(20) + +/* 2 AGGLEN_LMT_L */ +#define _AGGLMT_MCS0(x) ((x) & 0xF) +#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) + + +/* 2 RL */ +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + + +/* 2 DARFRC */ +#define _DARF_RC1(x) ((x) & 0x1F) +#define _DARF_RC2(x) (((x) & 0x1F) << 8) +#define _DARF_RC3(x) (((x) & 0x1F) << 16) +#define _DARF_RC4(x) (((x) & 0x1F) << 24) +/* NOTE: shift starting from address (DARFRC + 4) */ +#define _DARF_RC5(x) ((x) & 0x1F) +#define _DARF_RC6(x) (((x) & 0x1F) << 8) +#define _DARF_RC7(x) (((x) & 0x1F) << 16) +#define _DARF_RC8(x) (((x) & 0x1F) << 24) + + +/* 2 RARFRC */ +#define _RARF_RC1(x) ((x) & 0x1F) +#define _RARF_RC2(x) (((x) & 0x1F) << 8) +#define _RARF_RC3(x) (((x) & 0x1F) << 16) +#define _RARF_RC4(x) (((x) & 0x1F) << 24) +/* NOTE: shift starting from address (RARFRC + 4) */ +#define _RARF_RC5(x) ((x) & 0x1F) +#define _RARF_RC6(x) (((x) & 0x1F) << 8) +#define _RARF_RC7(x) (((x) & 0x1F) << 16) +#define _RARF_RC8(x) (((x) & 0x1F) << 24) + + +/* */ +/* */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* */ +/* */ + + + +/* 2 EDCA setting */ +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + + +/* 2 EDCA_VO_PARAM */ +#define _AIFS(x) (x) +#define _ECW_MAX_MIN(x) ((x) << 8) +#define _TXOP_LIMIT(x) ((x) << 16) + + +#define _BCNIFS(x) ((x) & 0xFF) +#define _BCNECW(x) (((x) & 0xF))<< 8) + + +#define _LRL(x) ((x) & 0x3F) +#define _SRL(x) (((x) & 0x3F) << 8) + + +/* 2 SIFS_CCK */ +#define _SIFS_CCK_CTX(x) ((x) & 0xFF) +#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8); + + +/* 2 SIFS_OFDM */ +#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) +#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8); + + +/* 2 TBTT PROHIBIT */ +#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) + + +/* 2 REG_RD_CTRL */ +#define DIS_EDCA_CNT_DWN BIT(11) + + +/* 2 BCN_CTRL */ +#define EN_MBSSID BIT(1) +#define EN_TXBCN_RPT BIT(2) +#define EN_BCN_FUNCTION BIT(3) +#define DIS_TSF_UPDATE BIT(3) + +/* The same function but different bit field. */ +#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) +#define DIS_TSF_UDT0_TEST_CHIP BIT(5) + +/* 2 ACMHWCTRL */ +#define AcmHw_HwEn BIT(0) +#define AcmHw_BeqEn BIT(1) +#define AcmHw_ViqEn BIT(2) +#define AcmHw_VoqEn BIT(3) +#define AcmHw_BeqStatus BIT(4) +#define AcmHw_ViqStatus BIT(5) +#define AcmHw_VoqStatus BIT(6) + + + +/* */ +/* */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* */ +/* */ + +/* 2 APSD_CTRL */ +#define APSDOFF BIT(6) +#define APSDOFF_STATUS BIT(7) + + +/* 2 BWOPMODE */ +#define BW_20MHZ BIT(2) + + +#define RATE_BITMAP_ALL 0xFFFFF + +/* Only use CCK 1M rate for ACK */ +#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 + +/* 2 TCR */ +#define TSFRST BIT(0) +#define DIS_GCLK BIT(1) +#define PAD_SEL BIT(2) +#define PWR_ST BIT(6) +#define PWRBIT_OW_EN BIT(7) +#define ACRC BIT(8) +#define CFENDFORM BIT(9) +#define ICV BIT(10) + + + +/* 2 RCR */ +#define AAP BIT(0) +#define APM BIT(1) +#define AM BIT(2) +#define AB BIT(3) +#define ADD3 BIT(4) +#define APWRMGT BIT(5) +#define CBSSID BIT(6) +#define CBSSID_BCN BIT(7) +#define ACRC32 BIT(8) +#define AICV BIT(9) +#define ADF BIT(11) +#define ACF BIT(12) +#define AMF BIT(13) +#define HTC_LOC_CTRL BIT(14) +#define UC_DATA_EN BIT(16) +#define BM_DATA_EN BIT(17) +#define MFBEN BIT(22) +#define LSIGEN BIT(23) +#define EnMBID BIT(24) +#define APP_BASSN BIT(27) +#define APP_PHYSTS BIT(28) +#define APP_ICV BIT(29) +#define APP_MIC BIT(30) +#define APP_FCS BIT(31) + +/* 2 RX_PKT_LIMIT */ + +/* 2 RX_DLK_TIME */ + +/* 2 MBIDCAMCFG */ + + + +/* 2 AMPDU_MIN_SPACE */ +#define _MIN_SPACE(x) ((x) & 0x7) +#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) + + +/* 2 RXERR_RPT */ +#define RXERR_TYPE_OFDM_PPDU 0 +#define RXERR_TYPE_OFDMfalse_ALARM 1 +#define RXERR_TYPE_OFDM_MPDU_OK 2 +#define RXERR_TYPE_OFDM_MPDU_FAIL 3 +#define RXERR_TYPE_CCK_PPDU 4 +#define RXERR_TYPE_CCKfalse_ALARM 5 +#define RXERR_TYPE_CCK_MPDU_OK 6 +#define RXERR_TYPE_CCK_MPDU_FAIL 7 +#define RXERR_TYPE_HT_PPDU 8 +#define RXERR_TYPE_HTfalse_ALARM 9 +#define RXERR_TYPE_HT_MPDU_TOTAL 10 +#define RXERR_TYPE_HT_MPDU_OK 11 +#define RXERR_TYPE_HT_MPDU_FAIL 12 +#define RXERR_TYPE_RX_FULL_DROP 15 + +#define RXERR_COUNTER_MASK 0xFFFFF +#define RXERR_RPT_RST BIT(27) +#define _RXERR_RPT_SEL(type) ((type) << 28) + + +/* 2 SECCFG */ +#define SCR_TxUseDK BIT(0) /* Force Tx Use Default Key */ +#define SCR_RxUseDK BIT(1) /* Force Rx Use Default Key */ +#define SCR_TxEncEnable BIT(2) /* Enable Tx Encryption */ +#define SCR_RxDecEnable BIT(3) /* Enable Rx Decryption */ +#define SCR_SKByA2 BIT(4) /* Search kEY BY A2 */ +#define SCR_NoSKMC BIT(5) /* No Key Search Multicast */ + + + +/* */ +/* */ +/* 0xFE00h ~ 0xFE55h USB Configuration */ +/* */ +/* */ + +/* 2 USB Information (0xFE17) */ +#define USB_IS_HIGH_SPEED 0 +#define USB_IS_FULL_SPEED 1 +#define USB_SPEED_MASK BIT(5) + +#define USB_NORMAL_SIE_EP_MASK 0xF +#define USB_NORMAL_SIE_EP_SHIFT 4 + +#define USB_TEST_EP_MASK 0x30 +#define USB_TEST_EP_SHIFT 4 + +/* 2 Special Option */ +#define USB_AGG_EN BIT(3) + + +/* 2REG_C2HEVT_CLEAR */ + /* Set by driver and notify FW that the driver has read the + C2H command message */ +#define C2H_EVT_HOST_CLOSE 0x00 + /* Set by FW indicating that FW had set the C2H command message + and it's not yet read by driver. */ +#define C2H_EVT_FW_CLOSE 0xFF + + +/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ + /* Enable GPIO[9] as WiFi HW PDn source */ +#define WL_HWPDN_EN BIT0 + /* WiFi HW PDn polarity control */ +#define WL_HWPDN_SL BIT1 + /* WiFi function enable */ +#define WL_FUNC_EN BIT2 + /* Enable GPIO[9] as WiFi RF HW PDn source */ +#define WL_HWROF_EN BIT3 + /* Enable GPIO[11] as BT HW PDn source */ +#define BT_HWPDN_EN BIT16 + /* BT HW PDn polarity control */ +#define BT_HWPDN_SL BIT17 + /* BT function enable */ +#define BT_FUNC_EN BIT18 + /* Enable GPIO[11] as BT/GPS RF HW PDn source */ +#define BT_HWROF_EN BIT19 + /* Enable GPIO[10] as GPS HW PDn source */ +#define GPS_HWPDN_EN BIT20 + /* GPS HW PDn polarity control */ +#define GPS_HWPDN_SL BIT21 + /* GPS function enable */ +#define GPS_FUNC_EN BIT22 + +/* 3 REG_LIFECTRL_CTRL */ +#define HAL92C_EN_PKT_LIFE_TIME_BK BIT3 +#define HAL92C_EN_PKT_LIFE_TIME_BE BIT2 +#define HAL92C_EN_PKT_LIFE_TIME_VI BIT1 +#define HAL92C_EN_PKT_LIFE_TIME_VO BIT0 + +#define HAL92C_MSDU_LIFE_TIME_UNIT 128 /* in us, said by Tim. */ + +/* */ +/* General definitions */ +/* */ + +#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 1000 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +/* */ +/* 8723A Regsiter offset definition */ +/* */ +#define HAL_8723A_NAV_UPPER_UNIT 128 /* micro-second */ + +/* */ +/* */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* */ +/* */ +#define REG_SYSON_REG_LOCK 0x001C + + +/* */ +/* */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* */ +/* */ +#define REG_FTIMR 0x0138 + + +/* */ +/* */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* */ +/* */ + + +/* */ +/* */ +/* 0x0280h ~ 0x02FFh RXDMA Configuration */ +/* */ +/* */ + + +/* */ +/* */ +/* 0x0300h ~ 0x03FFh PCIe */ +/* */ +/* */ + + +/* */ +/* */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* */ +/* */ +#define REG_EARLY_MODE_CONTROL 0x4D0 + + +/* */ +/* */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* */ +/* */ + +/* 2 BCN_CTRL */ +#define DIS_ATIM BIT(0) +#define DIS_BCNQ_SUB BIT(1) +#define DIS_TSF_UDT BIT(4) + + +/* */ +/* */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* */ +/* */ +/* */ +/* Note: */ +/* The NAV upper value is very important to WiFi 11n 5.2.3 NAV test. + * The default value is always too small, but the WiFi TestPlan test + * by 25,000 microseconds of NAV through sending CTS in the air. We + * must update this value greater than 25,000 microseconds to pass the + * item. +* The offset of NAV_UPPER in 8192C Spec is incorrect, and the offset +* should be 0x0652. Commented by SD1 Scott. */ +/* By Bruce, 2011-07-18. */ +/* */ +#define REG_NAV_UPPER 0x0652 /* unit of 128 */ + + +/* */ +/* 8723 Regsiter Bit and Content definition */ +/* */ + +/* */ +/* */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* */ +/* */ + +/* 2 SPS0_CTRL */ + +/* 2 SYS_ISO_CTRL */ + +/* 2 SYS_FUNC_EN */ + +/* 2 APS_FSMCO */ +#define EN_WLON BIT(16) + +/* 2 SYS_CLKR */ + +/* 2 9346CR */ + +/* 2 AFE_MISC */ + +/* 2 SPS0_CTRL */ + +/* 2 SPS_OCP_CFG */ + +/* 2 SYSON_REG_LOCK */ +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define WLOCK_1C_B6 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +/* 2 RF_CTRL */ + +/* 2 LDOA15_CTRL */ + +/* 2 LDOV12D_CTRL */ + +/* 2 AFE_XTAL_CTRL */ + +/* 2 AFE_PLL_CTRL */ + +/* 2 EFUSE_CTRL */ + +/* 2 EFUSE_TEST (For RTL8723 partially) */ + +/* 2 PWR_DATA */ + +/* 2 CAL_TIMER */ + +/* 2 ACLK_MON */ + +/* 2 GPIO_MUXCFG */ + +/* 2 GPIO_PIN_CTRL */ + +/* 2 GPIO_INTM */ + +/* 2 LEDCFG */ + +/* 2 FSIMR */ + +/* 2 FSISR */ + +/* 2 HSIMR */ +/* 8723 Host System Interrupt Mask Register (offset 0x58, 32 byte) */ +#define HSIMR_GPIO12_0_INT_EN BIT(0) +#define HSIMR_SPS_OCP_INT_EN BIT(5) +#define HSIMR_RON_INT_EN BIT(6) +#define HSIMR_PDNINT_EN BIT(7) +#define HSIMR_GPIO9_INT_EN BIT(25) + +/* 2 HSISR */ +/* 8723 Host System Interrupt Status Register (offset 0x5C, 32 byte) */ +#define HSISR_GPIO12_0_INT BIT(0) +#define HSISR_SPS_OCP_INT BIT(5) +#define HSISR_RON_INT BIT(6) +#define HSISR_PDNINT BIT(7) +#define HSISR_GPIO9_INT BIT(25) + +/* interrupt mask which needs to clear */ +#define MASK_HSISR_CLEAR (HSISR_GPIO12_0_INT | \ + HSISR_SPS_OCP_INT | \ + HSISR_RON_INT | \ + HSISR_PDNINT | \ + HSISR_GPIO9_INT) + +/* 2 MCUFWDL */ +#define RAM_DL_SEL BIT7 /* 1:RAM, 0:ROM */ + +/* 2 HPON_FSM */ + +/* 2 SYS_CFG */ +#define RTL_ID BIT(23) /* TestChip ID, + 1:Test(RLE); 0:MP(RL) */ +#define SPS_SEL BIT(24) /* 1:LDO regulator mode; + 0:Switching regulator mode*/ + + +/* */ +/* */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* */ +/* */ + +/* 2 Function Enable Registers */ + +/* 2 CR */ +#define CALTMR_EN BIT(10) + +/* 2 PBP - Page Size Register */ + +/* 2 TX/RXDMA */ + +/* 2 TRXFF_BNDY */ + +/* 2 LLT_INIT */ + +/* 2 BB_ACCESS_CTRL */ + + +/* */ +/* */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* */ +/* */ + +/* 2 RQPN */ + +/* 2 TDECTRL */ + +/* 2 TDECTL */ + +/* 2 TXDMA_OFFSET_CHK */ + + +/* */ +/* */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* */ +/* */ + +/* 2 FWHW_TXQ_CTRL */ + +/* 2 INIRTSMCS_SEL */ + +/* 2 SPEC SIFS */ + +/* 2 RRSR */ + +/* 2 ARFR */ + +/* 2 AGGLEN_LMT_L */ + +/* 2 RL */ + +/* 2 DARFRC */ + +/* 2 RARFRC */ + + +/* */ +/* */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* */ +/* */ + +/* 2 EDCA setting */ + +/* 2 EDCA_VO_PARAM */ + +/* 2 SIFS_CCK */ + +/* 2 SIFS_OFDM */ + +/* 2 TBTT PROHIBIT */ + +/* 2 REG_RD_CTRL */ + +/* 2 BCN_CTRL */ + +/* 2 ACMHWCTRL */ + + +/* */ +/* */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* */ +/* */ + +/* 2 APSD_CTRL */ + +/* 2 BWOPMODE */ + +/* 2 TCR */ + +/* 2 RCR */ + +/* 2 RX_PKT_LIMIT */ + +/* 2 RX_DLK_TIME */ + +/* 2 MBIDCAMCFG */ + +/* 2 AMPDU_MIN_SPACE */ + +/* 2 RXERR_RPT */ + +/* 2 SECCFG */ + + +/* */ +/* */ +/* 0xFE00h ~ 0xFE55h RTL8723 SDIO Configuration */ +/* */ +/* */ + +/* I/O bus domain address mapping */ +#define WLAN_IOREG_BASE 0x10260000 +#define FIRMWARE_FIFO_BASE 0x10270000 +#define TX_HIQ_BASE 0x10310000 +#define TX_MIQ_BASE 0x10320000 +#define TX_LOQ_BASE 0x10330000 +#define RX_RX0FF_BASE 0x10340000 + +/* SDIO host local register space mapping. */ +#define WLAN_IOREG_MSK 0x7FFF +#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */ +#define WLAN_RX0FF_MSK 0x0003 + +#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */ +#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */ + +/* 8723 EFUSE */ +#define HWSET_MAX_SIZE 256 + + +/* USB interrupt */ +#define UHIMR_TIMEOUT2 BIT31 +#define UHIMR_TIMEOUT1 BIT30 +#define UHIMR_PSTIMEOUT BIT29 +#define UHIMR_GTINT4 BIT28 +#define UHIMR_GTINT3 BIT27 +#define UHIMR_TXBCNERR BIT26 +#define UHIMR_TXBCNOK BIT25 +#define UHIMR_TSF_BIT32_TOGGLE BIT24 +#define UHIMR_BCNDMAINT3 BIT23 +#define UHIMR_BCNDMAINT2 BIT22 +#define UHIMR_BCNDMAINT1 BIT21 +#define UHIMR_BCNDMAINT0 BIT20 +#define UHIMR_BCNDOK3 BIT19 +#define UHIMR_BCNDOK2 BIT18 +#define UHIMR_BCNDOK1 BIT17 +#define UHIMR_BCNDOK0 BIT16 +#define UHIMR_HSISR_IND BIT15 +#define UHIMR_BCNDMAINT_E BIT14 +/* RSVD BIT13 */ +#define UHIMR_CTW_END BIT12 +/* RSVD BIT11 */ +#define UHIMR_C2HCMD BIT10 +#define UHIMR_CPWM2 BIT9 +#define UHIMR_CPWM BIT8 +#define UHIMR_HIGHDOK BIT7 /* High Queue DMA OK + Interrupt */ +#define UHIMR_MGNTDOK BIT6 /* Management Queue DMA OK + Interrupt */ +#define UHIMR_BKDOK BIT5 /* AC_BK DMA OK Interrupt */ +#define UHIMR_BEDOK BIT4 /* AC_BE DMA OK Interrupt */ +#define UHIMR_VIDOK BIT3 /* AC_VI DMA OK Interrupt */ +#define UHIMR_VODOK BIT2 /* AC_VO DMA Interrupt */ +#define UHIMR_RDU BIT1 /* Receive Descriptor + Unavailable */ +#define UHIMR_ROK BIT0 /* Receive DMA OK Interrupt */ + +/* USB Host Interrupt Status Extension bit */ +#define UHIMR_BCNDMAINT7 BIT23 +#define UHIMR_BCNDMAINT6 BIT22 +#define UHIMR_BCNDMAINT5 BIT21 +#define UHIMR_BCNDMAINT4 BIT20 +#define UHIMR_BCNDOK7 BIT19 +#define UHIMR_BCNDOK6 BIT18 +#define UHIMR_BCNDOK5 BIT17 +#define UHIMR_BCNDOK4 BIT16 +/* bit14-15: RSVD */ +#define UHIMR_ATIMEND_E BIT13 +#define UHIMR_ATIMEND BIT12 +#define UHIMR_TXERR BIT11 +#define UHIMR_RXERR BIT10 +#define UHIMR_TXFOVW BIT9 +#define UHIMR_RXFOVW BIT8 +/* bit2-7: RSVD */ +#define UHIMR_OCPINT BIT1 +/* bit0: RSVD */ + +#define REG_USB_HIMR 0xFE38 +#define REG_USB_HIMRE 0xFE3C +#define REG_USB_HISR 0xFE78 +#define REG_USB_HISRE 0xFE7C + +#define USB_INTR_CPWM_OFFSET 16 +#define USB_INTR_CONTENT_HISR_OFFSET 48 +#define USB_INTR_CONTENT_HISRE_OFFSET 52 +#define USB_INTR_CONTENT_LENGTH 56 +#define USB_C2H_CMDID_OFFSET 0 +#define USB_C2H_SEQ_OFFSET 1 +#define USB_C2H_EVENT_OFFSET 2 +/* */ +/* General definitions */ +/* */ + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_sreset.h b/drivers/staging/rtl8723au/include/rtl8723a_sreset.h new file mode 100644 index 000000000000..82af6a2704ed --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_sreset.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTL8723A_SRESET_H_ +#define _RTL8723A_SRESET_H_ + +#include +#include +#include + +void rtl8723a_sreset_xmit_status_check(struct rtw_adapter *padapter); +void rtl8723a_sreset_linked_status_check(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtl8723a_xmit.h b/drivers/staging/rtl8723au/include/rtl8723a_xmit.h new file mode 100644 index 000000000000..3b6fdc3a9b7b --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtl8723a_xmit.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTL8723A_XMIT_H__ +#define __RTL8723A_XMIT_H__ + +/* */ +/* Queue Select Value in TxDesc */ +/* */ +#define QSLT_BK 0x2/* 0x01 */ +#define QSLT_BE 0x0 +#define QSLT_VI 0x5/* 0x4 */ +#define QSLT_VO 0x7/* 0x6 */ +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +/* */ +/* defined for TX DESC Operation */ +/* */ + +#define MAX_TID (15) + +/* OFFSET 0 */ +#define OFFSET_SZ 0 +#define OFFSET_SHT 16 +#define BMC BIT(24) +#define LSG BIT(26) +#define FSG BIT(27) +#define OWN BIT(31) + + +/* OFFSET 4 */ +#define PKT_OFFSET_SZ 0 +#define BK BIT(6) +#define QSEL_SHT 8 +#define Rate_ID_SHT 16 +#define NAVUSEHDR BIT(20) +#define PKT_OFFSET_SHT 26 +#define HWPC BIT(31) + +/* OFFSET 8 */ +#define AGG_EN BIT(29) + +/* OFFSET 12 */ +#define SEQ_SHT 16 + +/* OFFSET 16 */ +#define QoS BIT(6) +#define HW_SEQ_EN BIT(7) +#define USERATE BIT(8) +#define DISDATAFB BIT(10) +#define DATA_SHORT BIT(24) +#define DATA_BW BIT(25) + +/* OFFSET 20 */ +#define SGI BIT(6) + +struct txdesc_8723a { + u32 pktlen:16; + u32 offset:8; + u32 bmc:1; + u32 htc:1; + u32 ls:1; + u32 fs:1; + u32 linip:1; + u32 noacm:1; + u32 gf:1; + u32 own:1; + + u32 macid:5; + u32 agg_en:1; + u32 bk:1; + u32 rd_en:1; + u32 qsel:5; + u32 rd_nav_ext:1; + u32 lsig_txop_en:1; + u32 pifs:1; + u32 rate_id:4; + u32 navusehdr:1; + u32 en_desc_id:1; + u32 sectype:2; + u32 rsvd0424:2; + u32 pkt_offset:5; /* unit: 8 bytes */ + u32 rsvd0431:1; + + u32 rts_rc:6; + u32 data_rc:6; + u32 rsvd0812:2; + u32 bar_rty_th:2; + u32 rsvd0816:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdu_density:3; + u32 bt_null:1; + u32 ant_sel_a:1; + u32 ant_sel_b:1; + u32 tx_ant_cck:2; + u32 tx_antl:2; + u32 tx_ant_ht:2; + + u32 nextheadpage:8; + u32 tailpage:8; + u32 seq:12; + u32 cpu_handle:1; + u32 tag1:1; + u32 trigger_int:1; + u32 hwseq_en:1; + + u32 rtsrate:5; + u32 ap_dcfe:1; + u32 hwseq_sel:2; + u32 userate:1; + u32 disrtsfb:1; + u32 disdatafb:1; + u32 cts2self:1; + u32 rtsen:1; + u32 hw_rts_en:1; + u32 port_id:1; + u32 rsvd1615:3; + u32 wait_dcts:1; + u32 cts2ap_en:1; + u32 data_sc:2; + u32 data_stbc:2; + u32 data_short:1; + u32 data_bw:1; + u32 rts_short:1; + u32 rts_bw:1; + u32 rts_sc:2; + u32 vcs_stbc:2; + + u32 datarate:6; + u32 sgi:1; + u32 try_rate:1; + u32 data_ratefb_lmt:5; + u32 rts_ratefb_lmt:4; + u32 rty_lmt_en:1; + u32 data_rt_lmt:6; + u32 usb_txagg_num:8; + + u32 txagg_a:5; + u32 txagg_b:5; + u32 use_max_len:1; + u32 max_agg_num:5; + u32 mcsg1_max_len:4; + u32 mcsg2_max_len:4; + u32 mcsg3_max_len:4; + u32 mcs7_sgi_max_len:4; + + u32 checksum:16; /* TxBuffSize(PCIe)/CheckSum(USB) */ + u32 mcsg4_max_len:4; + u32 mcsg5_max_len:4; + u32 mcsg6_max_len:4; + u32 mcs15_sgi_max_len:4; +}; + +#define txdesc_set_ccx_sw_8723a(txdesc, value) \ + do { \ + ((struct txdesc_8723a *)(txdesc))->mcsg4_max_len = (((value)>>8) & 0x0f); \ + ((struct txdesc_8723a *)(txdesc))->mcs15_sgi_max_len= (((value)>>4) & 0x0f); \ + ((struct txdesc_8723a *)(txdesc))->mcsg6_max_len = ((value) & 0x0f); \ + } while (0) + +struct txrpt_ccx_8723a { + /* offset 0 */ + u8 tag1:1; + u8 rsvd:4; + u8 int_bt:1; + u8 int_tri:1; + u8 int_ccx:1; + + /* offset 1 */ + u8 mac_id:5; + u8 pkt_drop:1; + u8 pkt_ok:1; + u8 bmc:1; + + /* offset 2 */ + u8 retry_cnt:6; + u8 lifetime_over:1; + u8 retry_over:1; + + /* offset 3 */ + u8 ccx_qtime0; + u8 ccx_qtime1; + + /* offset 5 */ + u8 final_data_rate; + + /* offset 6 */ + u8 sw1:4; + u8 qsel:4; + + /* offset 7 */ + u8 sw0; +}; + +#define txrpt_ccx_sw_8723a(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8)) +#define txrpt_ccx_qtime_8723a(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8)) + +void dump_txrpt_ccx_8723a(void *buf); +void handle_txrpt_ccx_8723a(struct rtw_adapter *adapter, void *buf); +void rtl8723a_update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem); +void rtl8723a_fill_fake_txdesc(struct rtw_adapter *padapter, u8 *pDesc, u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull); + +s32 rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe); +s32 rtl8723au_xmit_buf_handler(struct rtw_adapter *padapter); +#define hal_xmit_handler rtl8723au_xmit_buf_handler +s32 rtl8723au_init_xmit_priv(struct rtw_adapter * padapter); +void rtl8723au_free_xmit_priv(struct rtw_adapter * padapter); +s32 rtl8723au_hal_xmit(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe); +s32 rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe); +s32 rtl8723au_xmitframe_complete(struct rtw_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); + + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_ap.h b/drivers/staging/rtl8723au/include/rtw_ap.h new file mode 100644 index 000000000000..76f82d68f633 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_ap.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_AP_H_ +#define __RTW_AP_H_ + +#include +#include + + +#ifdef CONFIG_8723AU_AP_MODE + +/* external function */ +void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta); +void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta); + +void init_mlme_ap_info23a(struct rtw_adapter *padapter); +void free_mlme_ap_info23a(struct rtw_adapter *padapter); +/* void update_BCNTIM(struct rtw_adapter *padapter); */ +void rtw_add_bcn_ie(struct rtw_adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len); +void rtw_remove_bcn_ie(struct rtw_adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index); +void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx); +void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_level); +void expire_timeout_chk23a(struct rtw_adapter *padapter); +void update_sta_info23a_apmode23a(struct rtw_adapter *padapter, struct sta_info *psta); +int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len); +void rtw_ap_restore_network(struct rtw_adapter *padapter); +void rtw_set_macaddr_acl23a(struct rtw_adapter *padapter, int mode); +int rtw_acl_add_sta23a(struct rtw_adapter *padapter, u8 *addr); +int rtw_acl_remove_sta23a(struct rtw_adapter *padapter, u8 *addr); + +void associated_clients_update23a(struct rtw_adapter *padapter, u8 updated); +void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info *psta); +u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info *psta); +void sta_info_update23a(struct rtw_adapter *padapter, struct sta_info *psta); +void ap_sta_info_defer_update23a(struct rtw_adapter *padapter, struct sta_info *psta); +u8 ap_free_sta23a(struct rtw_adapter *padapter, struct sta_info *psta, bool active, u16 reason); +int rtw_sta_flush23a(struct rtw_adapter *padapter); +int rtw_ap_inform_ch_switch23a(struct rtw_adapter *padapter, u8 new_ch, u8 ch_offset); +void start_ap_mode23a(struct rtw_adapter *padapter); +void stop_ap_mode23a(struct rtw_adapter *padapter); +#endif /* end of CONFIG_8723AU_AP_MODE */ + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_cmd.h b/drivers/staging/rtl8723au/include/rtw_cmd.h new file mode 100644 index 000000000000..f9caa3e35f57 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_cmd.h @@ -0,0 +1,835 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_CMD_H_ +#define __RTW_CMD_H_ + +#include +#include +#include + +#define C2H_MEM_SZ (16*1024) + +#include +#include /* */ + + +#define FREE_CMDOBJ_SZ 128 + +#define MAX_CMDSZ 1024 +#define MAX_RSPSZ 512 +#define MAX_EVTSZ 1024 + +#define CMDBUFF_ALIGN_SZ 512 + +struct cmd_obj { + struct rtw_adapter *padapter; + u16 cmdcode; + u8 res; + u8 *parmbuf; + u32 cmdsz; + u8 *rsp; + u32 rspsz; + /* struct semaphore cmd_sem; */ + struct list_head list; +}; + +struct cmd_priv { + struct semaphore cmd_queue_sema; + /* struct semaphore cmd_done_sema; */ + struct semaphore terminate_cmdthread_sema; + struct rtw_queue cmd_queue; + u8 cmd_seq; + u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */ + u8 *cmd_allocated_buf; + u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */ + u8 *rsp_allocated_buf; + u32 cmd_issued_cnt; + u32 cmd_done_cnt; + u32 rsp_cnt; + u8 cmdthd_running; + struct rtw_adapter *padapter; +}; + +#define C2H_QUEUE_MAX_LEN 10 + +struct evt_priv { + struct work_struct c2h_wk; + bool c2h_wk_alive; + struct rtw_cbuf *c2h_queue; + + atomic_t event_seq; + u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ + u8 *evt_allocated_buf; + u32 evt_done_cnt; +}; + +#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ +do {\ + INIT_LIST_HEAD(&pcmd->list);\ + pcmd->cmdcode = code;\ + pcmd->parmbuf = (u8 *)(pparm);\ + pcmd->cmdsz = sizeof (*pparm);\ + pcmd->rsp = NULL;\ + pcmd->rspsz = 0;\ +} while(0) + +struct c2h_evt_hdr { + u8 id:4; + u8 plen:4; + u8 seq; + u8 payload[0]; +}; + +#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) + +u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); +void rtw_free_cmd_obj23a(struct cmd_obj *pcmd); + +int rtw_cmd_thread23a(void *context); + +int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv); +void rtw_free_cmd_priv23a (struct cmd_priv *pcmdpriv); + +u32 rtw_init_evt_priv23a (struct evt_priv *pevtpriv); +void rtw_free_evt_priv23a (struct evt_priv *pevtpriv); +void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv); +void rtw_evt_notify_isr(struct evt_priv *pevtpriv); +#ifdef CONFIG_8723AU_P2P +u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType ); +#endif /* CONFIG_8723AU_P2P */ + +enum rtw_drvextra_cmd_id +{ + NONE_WK_CID, + DYNAMIC_CHK_WK_CID, + DM_CTRL_WK_CID, + PBC_POLLING_WK_CID, + POWER_SAVING_CTRL_WK_CID,/* IPS,AUTOSuspend */ + LPS_CTRL_WK_CID, + ANT_SELECT_WK_CID, + P2P_PS_WK_CID, + P2P_PROTO_WK_CID, + CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */ + C2H_WK_CID, + RTP_TIMER_CFG_WK_CID, + MAX_WK_CID +}; + +enum LPS_CTRL_TYPE +{ + LPS_CTRL_SCAN=0, + LPS_CTRL_JOINBSS=1, + LPS_CTRL_CONNECT=2, + LPS_CTRL_DISCONNECT=3, + LPS_CTRL_SPECIAL_PACKET=4, + LPS_CTRL_LEAVE=5, +}; + +enum RFINTFS { + SWSI, + HWSI, + HWPI, +}; + +/* +Caller Mode: Infra, Ad-HoC(C) + +Notes: To enter USB suspend mode + +Command Mode + +*/ +struct usb_suspend_parm { + u32 action;/* 1: sleep, 0:resume */ +}; + +/* +Caller Mode: Infra, Ad-HoC + +Notes: To join a known BSS. + +Command-Event Mode + +*/ + +/* +Caller Mode: Infra, Ad-HoC(C) + +Notes: To disconnect the current associated BSS + +Command Mode + +*/ +struct disconnect_parm { + u32 deauth_timeout_ms; +}; + +struct setopmode_parm { + u8 mode; + u8 rsvd[3]; +}; + +/* +Caller Mode: AP, Ad-HoC, Infra + +Notes: To ask RTL8711 performing site-survey + +Command-Event Mode + +*/ + +#define RTW_SSID_SCAN_AMOUNT 9 /* for WEXT_CSCAN_AMOUNT 9 */ +#define RTW_CHANNEL_SCAN_AMOUNT (14+37) +struct sitesurvey_parm { + int scan_mode; /* active: 1, passive: 0 */ + u8 ssid_num; + u8 ch_num; + struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT]; + struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; +}; + +/* +Caller Mode: Any + +Notes: To set the auth type of RTL8711. open/shared/802.1x + +Command Mode + +*/ +struct setauth_parm { + u8 mode; /* 0: legacy open, 1: legacy shared 2: 802.1x */ + u8 _1x; /* 0: PSK, 1: TLS */ + u8 rsvd[2]; +}; + +/* +Caller Mode: Infra + +a. algorithm: wep40, wep104, tkip & aes +b. keytype: grp key/unicast key +c. key contents + +when shared key ==> keyid is the camid +when 802.1x ==> keyid [0:1] ==> grp key +when 802.1x ==> keyid > 2 ==> unicast key + +*/ +struct setkey_parm { + u8 algorithm; /* encryption algorithm, could be none, wep40, TKIP, CCMP, wep104 */ + u8 keyid; + u8 grpkey; /* 1: this is the grpkey for 802.1x. 0: this is the unicast key for 802.1x */ + u8 set_tx; /* 1: main tx key for wep. 0: other key. */ + u8 key[16]; /* this could be 40 or 104 */ +}; + +/* +When in AP or Ad-Hoc mode, this is used to +allocate an sw/hw entry for a newly associated sta. + +Command + +when shared key ==> algorithm/keyid + +*/ +struct set_stakey_parm { + u8 addr[ETH_ALEN]; + u8 algorithm; + u8 id;/* currently for erasing cam entry if algorithm == _NO_PRIVACY_ */ + u8 key[16]; +}; + +struct set_stakey_rsp { + u8 addr[ETH_ALEN]; + u8 keyid; + u8 rsvd; +}; + +/* +Caller Ad-Hoc/AP + +Command -Rsp(AID == CAMID) mode + +This is to force fw to add an sta_data entry per driver's request. + +FW will write an cam entry associated with it. + +*/ +struct set_assocsta_parm { + u8 addr[ETH_ALEN]; +}; + +struct set_assocsta_rsp { + u8 cam_id; + u8 rsvd[3]; +}; + +/* + Caller Ad-Hoc/AP + + Command mode + + This is to force fw to del an sta_data entry per driver's request + + FW will invalidate the cam entry associated with it. + +*/ +struct del_assocsta_parm { + u8 addr[ETH_ALEN]; +}; + +/* +Caller Mode: AP/Ad-HoC(M) + +Notes: To notify fw that given staid has changed its power state + +Command Mode + +*/ +struct setstapwrstate_parm { + u8 staid; + u8 status; + u8 hwaddr[6]; +}; + +/* +Caller Mode: Any + +Notes: To setup the basic rate of RTL8711 + +Command Mode + +*/ +struct setbasicrate_parm { + u8 basicrates[NumRates]; +}; + +/* +Caller Mode: Any + +Notes: To read the current basic rate + +Command-Rsp Mode + +*/ +struct getbasicrate_parm { + u32 rsvd; +}; + +struct getbasicrate_rsp { + u8 basicrates[NumRates]; +}; + +/* +Caller Mode: Any + +Notes: To setup the data rate of RTL8711 + +Command Mode + +*/ +struct setdatarate_parm { + u8 mac_id; + u8 datarates[NumRates]; +}; + +/* +Caller Mode: Any + +Notes: To read the current data rate + +Command-Rsp Mode + +*/ +struct getdatarate_parm { + u32 rsvd; +}; + +struct getdatarate_rsp { + u8 datarates[NumRates]; +}; + + +/* +Caller Mode: Any +AP: AP can use the info for the contents of beacon frame +Infra: STA can use the info when sitesurveying +Ad-HoC(M): Like AP +Ad-HoC(C): Like STA + + +Notes: To set the phy capability of the NIC + +Command Mode + +*/ + +struct setphyinfo_parm { + struct regulatory_class class_sets[NUM_REGULATORYS]; + u8 status; +}; + +struct getphyinfo_parm { + u32 rsvd; +}; + +struct getphyinfo_rsp { + struct regulatory_class class_sets[NUM_REGULATORYS]; + u8 status; +}; + +/* +Caller Mode: Any + +Notes: To set the channel/modem/band +This command will be used when channel/modem/band is changed. + +Command Mode + +*/ +struct setphy_parm { + u8 rfchannel; + u8 modem; +}; + +/* +Caller Mode: Any + +Notes: To get the current setting of channel/modem/band + +Command-Rsp Mode + +*/ +struct getphy_parm { + u32 rsvd; +}; + +struct getphy_rsp { + u8 rfchannel; + u8 modem; +}; + +struct readBB_parm { + u8 offset; +}; + +struct readBB_rsp { + u8 value; +}; + +struct readTSSI_parm { + u8 offset; +}; + +struct readTSSI_rsp { + u8 value; +}; + +struct writeBB_parm { + u8 offset; + u8 value; +}; + +struct readRF_parm { + u8 offset; +}; + +struct readRF_rsp { + u32 value; +}; + +struct writeRF_parm { + u32 offset; + u32 value; +}; + +struct getrfintfs_parm { + u8 rfintfs; +}; + +struct Tx_Beacon_param +{ + struct wlan_bssid_ex network; +}; + +/* CMD param Formart for driver extra cmd handler */ +struct drvextra_cmd_parm { + int ec_id; /* extra cmd id */ + int type_size; /* Can use this field as the type id or command size */ + unsigned char *pbuf; +}; + +/*------------------- Below are used for RF/BB tunning ---------------------*/ + +struct setantenna_parm { + u8 tx_antset; + u8 rx_antset; + u8 tx_antenna; + u8 rx_antenna; +}; + +struct enrateadaptive_parm { + u32 en; +}; + +struct settxagctbl_parm { + u32 txagc[MAX_RATES_LENGTH]; +}; + +struct gettxagctbl_parm { + u32 rsvd; +}; + +struct gettxagctbl_rsp { + u32 txagc[MAX_RATES_LENGTH]; +}; + +struct setagcctrl_parm { + u32 agcctrl; /* 0: pure hw, 1: fw */ +}; + +struct setssup_parm { + u32 ss_ForceUp[MAX_RATES_LENGTH]; +}; + +struct getssup_parm { + u32 rsvd; +}; + +struct getssup_rsp { + u8 ss_ForceUp[MAX_RATES_LENGTH]; +}; + +struct setssdlevel_parm { + u8 ss_DLevel[MAX_RATES_LENGTH]; +}; + +struct getssdlevel_parm { + u32 rsvd; +}; + +struct getssdlevel_rsp { + u8 ss_DLevel[MAX_RATES_LENGTH]; +}; + +struct setssulevel_parm { + u8 ss_ULevel[MAX_RATES_LENGTH]; +}; + +struct getssulevel_parm { + u32 rsvd; +}; + +struct getssulevel_rsp { + u8 ss_ULevel[MAX_RATES_LENGTH]; +}; + +struct setcountjudge_parm { + u8 count_judge[MAX_RATES_LENGTH]; +}; + +struct getcountjudge_parm { + u32 rsvd; +}; + +struct getcountjudge_rsp { + u8 count_judge[MAX_RATES_LENGTH]; +}; + +struct setratable_parm { + u8 ss_ForceUp[NumRates]; + u8 ss_ULevel[NumRates]; + u8 ss_DLevel[NumRates]; + u8 count_judge[NumRates]; +}; + +struct getratable_parm { + uint rsvd; +}; + +struct getratable_rsp { + u8 ss_ForceUp[NumRates]; + u8 ss_ULevel[NumRates]; + u8 ss_DLevel[NumRates]; + u8 count_judge[NumRates]; +}; + +/* to get TX,RX retry count */ +struct gettxretrycnt_parm{ + unsigned int rsvd; +}; +struct gettxretrycnt_rsp{ + unsigned long tx_retrycnt; +}; + +struct getrxretrycnt_parm{ + unsigned int rsvd; +}; +struct getrxretrycnt_rsp{ + unsigned long rx_retrycnt; +}; + +/* to get BCNOK,BCNERR count */ +struct getbcnokcnt_parm{ + unsigned int rsvd; +}; +struct getbcnokcnt_rsp{ + unsigned long bcnokcnt; +}; + +struct getbcnerrcnt_parm{ + unsigned int rsvd; +}; +struct getbcnerrcnt_rsp{ + unsigned long bcnerrcnt; +}; + +/* to get current TX power level */ +struct getcurtxpwrlevel_parm{ + unsigned int rsvd; +}; + +struct getcurtxpwrlevel_rsp{ + unsigned short tx_power; +}; + +struct setprobereqextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setassocreqextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setproberspextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct setassocrspextraie_parm { + unsigned char e_id; + unsigned char ie_len; + unsigned char ie[0]; +}; + +struct addBaReq_parm { + unsigned int tid; + u8 addr[ETH_ALEN]; +}; + +/*H2C Handler index: 46 */ +struct set_ch_parm { + u8 ch; + u8 bw; + u8 ch_offset; +}; + +/*H2C Handler index: 59 */ +struct SetChannelPlan_param { + u8 channel_plan; +}; + +/*H2C Handler index: 60 */ +struct LedBlink_param { + struct led_8723a *pLed; +}; + +/*H2C Handler index: 61 */ +struct SetChannelSwitch_param { + u8 new_ch_no; +}; + +/*H2C Handler index: 62 */ +struct TDLSoption_param { + u8 addr[ETH_ALEN]; + u8 option; +}; + +#define GEN_CMD_CODE(cmd) cmd ## _CMD_ + + +/* + +Result: +0x00: success +0x01: sucess, and check Response. +0x02: cmd ignored due to duplicated sequcne number +0x03: cmd dropped due to invalid cmd code +0x04: reserved. + +*/ + +#define H2C_RSP_OFFSET 512 + +#define H2C_SUCCESS 0x00 +#define H2C_SUCCESS_RSP 0x01 +#define H2C_DUPLICATED 0x02 +#define H2C_DROPPED 0x03 +#define H2C_PARAMETERS_ERROR 0x04 +#define H2C_REJECTED 0x05 +#define H2C_CMD_OVERFLOW 0x06 +#define H2C_RESERVED 0x07 + +u8 rtw_setassocsta_cmd(struct rtw_adapter *padapter, u8 *mac_addr); +u8 rtw_setstandby_cmd(struct rtw_adapter *padapter, uint action); +u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter, struct cfg80211_ssid *ssid, int ssid_num, struct rtw_ieee80211_channel *ch, int ch_num); +u8 rtw_createbss_cmd23a(struct rtw_adapter *padapter); +u8 rtw_createbss_cmd23a_ex(struct rtw_adapter *padapter, unsigned char *pbss, unsigned int sz); +u8 rtw_setphy_cmd(struct rtw_adapter *padapter, u8 modem, u8 ch); +u8 rtw_setstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 unicast_key); +u8 rtw_clearstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 entry, u8 enqueue); +u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter, struct wlan_network* pnetwork); +u8 rtw_disassoc_cmd23a(struct rtw_adapter *padapter, u32 deauth_timeout_ms, bool enqueue); +u8 rtw_setopmode_cmd23a(struct rtw_adapter *padapter, enum ndis_802_11_net_infra networktype); +u8 rtw_setdatarate_cmd(struct rtw_adapter *padapter, u8 *rateset); +u8 rtw_setbasicrate_cmd(struct rtw_adapter *padapter, u8 *rateset); +u8 rtw_setbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 val); +u8 rtw_setrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u32 val); +u8 rtw_getbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval); +u8 rtw_getrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval); +u8 rtw_setrfintfs_cmd(struct rtw_adapter *padapter, u8 mode); +u8 rtw_setrttbl_cmd(struct rtw_adapter *padapter, struct setratable_parm *prate_table); +u8 rtw_getrttbl_cmd(struct rtw_adapter *padapter, struct getratable_rsp *pval); + +u8 rtw_gettssi_cmd(struct rtw_adapter *padapter, u8 offset,u8 *pval); +u8 rtw_setfwdig_cmd(struct rtw_adapter*padapter, u8 type); +u8 rtw_setfwra_cmd(struct rtw_adapter*padapter, u8 type); + +u8 rtw_addbareq_cmd23a(struct rtw_adapter*padapter, u8 tid, u8 *addr); + +u8 rtw_dynamic_chk_wk_cmd23a(struct rtw_adapter *adapter); + +u8 rtw_lps_ctrl_wk_cmd23a(struct rtw_adapter*padapter, u8 lps_ctrl_type, u8 enqueue); + +u8 rtw_ps_cmd23a(struct rtw_adapter*padapter); + +#ifdef CONFIG_8723AU_AP_MODE +u8 rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter); +#endif + +u8 rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue); +u8 rtw_set_chplan_cmd(struct rtw_adapter*padapter, u8 chplan, u8 enqueue); +u8 rtw_led_blink_cmd(struct rtw_adapter*padapter, struct led_8723a *pLed); +u8 rtw_set_csa_cmd(struct rtw_adapter*padapter, u8 new_ch_no); +u8 rtw_tdls_cmd(struct rtw_adapter*padapter, u8 *addr, u8 option); + +u8 rtw_c2h_wk_cmd23a(struct rtw_adapter *padapter, u8 *c2h_evt); + +u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); + +void rtw_survey_cmd_callback23a(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_disassoc_cmd23a_callback(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_joinbss_cmd23a_callback(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_createbss_cmd23a_callback(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_getbbrfreg_cmdrsp_callback23a(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_readtssi_cmdrsp_callback(struct rtw_adapter* padapter, struct cmd_obj *pcmd); + +void rtw_setstaKey_cmdrsp_callback23a(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_setassocsta_cmdrsp_callback23a(struct rtw_adapter *padapter, struct cmd_obj *pcmd); +void rtw_getrttbl_cmdrsp_callback(struct rtw_adapter *padapter, struct cmd_obj *pcmd); + +struct _cmd_callback { + u32 cmd_code; + void (*callback)(struct rtw_adapter *padapter, struct cmd_obj *cmd); +}; + +enum rtw_h2c_cmd { + GEN_CMD_CODE(_Read_MACREG) , /*0*/ + GEN_CMD_CODE(_Write_MACREG) , + GEN_CMD_CODE(_Read_BBREG) , + GEN_CMD_CODE(_Write_BBREG) , + GEN_CMD_CODE(_Read_RFREG) , + GEN_CMD_CODE(_Write_RFREG) , /*5*/ + GEN_CMD_CODE(_Read_EEPROM) , + GEN_CMD_CODE(_Write_EEPROM) , + GEN_CMD_CODE(_Read_EFUSE) , + GEN_CMD_CODE(_Write_EFUSE) , + + GEN_CMD_CODE(_Read_CAM) , /*10*/ + GEN_CMD_CODE(_Write_CAM) , + GEN_CMD_CODE(_setBCNITV), + GEN_CMD_CODE(_setMBIDCFG), + GEN_CMD_CODE(_JoinBss), /*14*/ + GEN_CMD_CODE(_DisConnect) , /*15*/ + GEN_CMD_CODE(_CreateBss) , + GEN_CMD_CODE(_SetOpMode) , + GEN_CMD_CODE(_SiteSurvey), /*18*/ + GEN_CMD_CODE(_SetAuth) , + + GEN_CMD_CODE(_SetKey) , /*20*/ + GEN_CMD_CODE(_SetStaKey) , + GEN_CMD_CODE(_SetAssocSta) , + GEN_CMD_CODE(_DelAssocSta) , + GEN_CMD_CODE(_SetStaPwrState) , + GEN_CMD_CODE(_SetBasicRate) , /*25*/ + GEN_CMD_CODE(_GetBasicRate) , + GEN_CMD_CODE(_SetDataRate) , + GEN_CMD_CODE(_GetDataRate) , + GEN_CMD_CODE(_SetPhyInfo) , + + GEN_CMD_CODE(_GetPhyInfo) , /*30*/ + GEN_CMD_CODE(_SetPhy) , + GEN_CMD_CODE(_GetPhy) , + GEN_CMD_CODE(_readRssi) , + GEN_CMD_CODE(_readGain) , + GEN_CMD_CODE(_SetAtim) , /*35*/ + GEN_CMD_CODE(_SetPwrMode) , + GEN_CMD_CODE(_JoinbssRpt), + GEN_CMD_CODE(_SetRaTable) , + GEN_CMD_CODE(_GetRaTable) , + + GEN_CMD_CODE(_GetCCXReport), /*40*/ + GEN_CMD_CODE(_GetDTMReport), + GEN_CMD_CODE(_GetTXRateStatistics), + GEN_CMD_CODE(_SetUsbSuspend), + GEN_CMD_CODE(_SetH2cLbk), + GEN_CMD_CODE(_AddBAReq) , /*45*/ + GEN_CMD_CODE(_SetChannel), /*46*/ + GEN_CMD_CODE(_SetTxPower), + GEN_CMD_CODE(_SwitchAntenna), + GEN_CMD_CODE(_SetCrystalCap), + GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ + + GEN_CMD_CODE(_SetSingleToneTx),/*51*/ + GEN_CMD_CODE(_SetCarrierSuppressionTx), + GEN_CMD_CODE(_SetContinuousTx), + GEN_CMD_CODE(_SwitchBandwidth), /*54*/ + GEN_CMD_CODE(_TX_Beacon), /*55*/ + + GEN_CMD_CODE(_Set_MLME_EVT), /*56*/ + GEN_CMD_CODE(_Set_Drv_Extra), /*57*/ + GEN_CMD_CODE(_Set_H2C_MSG), /*58*/ + + GEN_CMD_CODE(_SetChannelPlan), /*59*/ + GEN_CMD_CODE(_LedBlink), /*60*/ + + GEN_CMD_CODE(_SetChannelSwitch), /*61*/ + GEN_CMD_CODE(_TDLS), /*62*/ + + MAX_H2CCMD +}; + +#define _GetBBReg_CMD_ _Read_BBREG_CMD_ +#define _SetBBReg_CMD_ _Write_BBREG_CMD_ +#define _GetRFReg_CMD_ _Read_RFREG_CMD_ +#define _SetRFReg_CMD_ _Write_RFREG_CMD_ + +extern struct _cmd_callback rtw_cmd_callback[]; + +#endif /* _CMD_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_debug.h b/drivers/staging/rtl8723au/include/rtw_debug.h new file mode 100644 index 000000000000..a69d6e215b8b --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_debug.h @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __RTW_DEBUG_H__ +#define __RTW_DEBUG_H__ + +#include +#include + +#define _drv_always_ 1 +#define _drv_emerg_ 2 +#define _drv_alert_ 3 +#define _drv_err_ 4 +#define _drv_warning_ 5 +#define _drv_notice_ 6 +#define _drv_info_ 7 +#define _drv_debug_ 8 + +#define _module_rtl871x_xmit_c_ BIT(0) +#define _module_xmit_osdep_c_ BIT(1) +#define _module_rtl871x_recv_c_ BIT(2) +#define _module_recv_osdep_c_ BIT(3) +#define _module_rtl871x_mlme_c_ BIT(4) +#define _module_mlme_osdep_c_ BIT(5) +#define _module_rtl871x_sta_mgt_c_ BIT(6) +#define _module_rtl871x_cmd_c_ BIT(7) +#define _module_cmd_osdep_c_ BIT(8) +#define _module_rtl871x_io_c_ BIT(9) +#define _module_io_osdep_c_ BIT(10) +#define _module_os_intfs_c_ BIT(11) +#define _module_rtl871x_security_c_ BIT(12) +#define _module_rtl871x_eeprom_c_ BIT(13) +#define _module_hal_init_c_ BIT(14) +#define _module_hci_hal_init_c_ BIT(15) +#define _module_rtl871x_ioctl_c_ BIT(16) +#define _module_rtl871x_ioctl_set_c_ BIT(17) +#define _module_rtl871x_ioctl_query_c_ BIT(18) +#define _module_rtl871x_pwrctrl_c_ BIT(19) +#define _module_hci_intfs_c_ BIT(20) +#define _module_hci_ops_c_ BIT(21) +#define _module_osdep_service_c_ BIT(22) +#define _module_mp_ BIT(23) +#define _module_hci_ops_os_c_ BIT(24) +#define _module_rtl871x_ioctl_os_c BIT(25) +#define _module_rtl8712_cmd_c_ BIT(26) +#define _module_rtl8192c_xmit_c_ BIT(28) +#define _module_hal_xmit_c_ BIT(28) /* duplication intentional */ +#define _module_efuse_ BIT(29) +#define _module_rtl8712_recv_c_ BIT(30) +#define _module_rtl8712_led_c_ BIT(31) + +#undef _MODULE_DEFINE_ + +#if defined _RTW_XMIT_C_ + #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_ +#elif defined _XMIT_OSDEP_C_ + #define _MODULE_DEFINE_ _module_xmit_osdep_c_ +#elif defined _RTW_RECV_C_ + #define _MODULE_DEFINE_ _module_rtl871x_recv_c_ +#elif defined _RECV_OSDEP_C_ + #define _MODULE_DEFINE_ _module_recv_osdep_c_ +#elif defined _RTW_MLME_C_ + #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_ +#elif defined _MLME_OSDEP_C_ + #define _MODULE_DEFINE_ _module_mlme_osdep_c_ +#elif defined _RTW_MLME_EXT_C_ + #define _MODULE_DEFINE_ 1 +#elif defined _RTW_STA_MGT_C_ + #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_ +#elif defined _RTW_CMD_C_ + #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_ +#elif defined _CMD_OSDEP_C_ + #define _MODULE_DEFINE_ _module_cmd_osdep_c_ +#elif defined _RTW_IO_C_ + #define _MODULE_DEFINE_ _module_rtl871x_io_c_ +#elif defined _IO_OSDEP_C_ + #define _MODULE_DEFINE_ _module_io_osdep_c_ +#elif defined _OS_INTFS_C_ + #define _MODULE_DEFINE_ _module_os_intfs_c_ +#elif defined _RTW_SECURITY_C_ + #define _MODULE_DEFINE_ _module_rtl871x_security_c_ +#elif defined _RTW_EEPROM_C_ + #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_ +#elif defined _HAL_INTF_C_ + #define _MODULE_DEFINE_ _module_hal_init_c_ +#elif (defined _HCI_HAL_INIT_C_) || (defined _SDIO_HALINIT_C_) + #define _MODULE_DEFINE_ _module_hci_hal_init_c_ +#elif defined _RTL871X_IOCTL_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_ +#elif defined _RTL871X_IOCTL_SET_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_ +#elif defined _RTL871X_IOCTL_QUERY_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_query_c_ +#elif defined _RTL871X_PWRCTRL_C_ + #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_ +#elif defined _RTW_PWRCTRL_C_ + #define _MODULE_DEFINE_ 1 +#elif defined _HCI_INTF_C_ + #define _MODULE_DEFINE_ _module_hci_intfs_c_ +#elif defined _HCI_OPS_C_ + #define _MODULE_DEFINE_ _module_hci_ops_c_ +#elif defined _SDIO_OPS_C_ + #define _MODULE_DEFINE_ 1 +#elif defined _OSDEP_HCI_INTF_C_ + #define _MODULE_DEFINE_ _module_hci_intfs_c_ +#elif defined _OSDEP_SERVICE_C_ + #define _MODULE_DEFINE_ _module_osdep_service_c_ +#elif defined _HCI_OPS_OS_C_ + #define _MODULE_DEFINE_ _module_hci_ops_os_c_ +#elif defined _RTL871X_IOCTL_LINUX_C_ + #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c +#elif defined _RTL8712_CMD_C_ + #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_ +#elif defined _RTL8192C_XMIT_C_ + #define _MODULE_DEFINE_ 1 +#elif defined _RTL8723AS_XMIT_C_ + #define _MODULE_DEFINE_ 1 +#elif defined _RTL8712_RECV_C_ + #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ +#elif defined _RTL8192CU_RECV_C_ + #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ +#elif defined _RTL871X_MLME_EXT_C_ + #define _MODULE_DEFINE_ _module_mlme_osdep_c_ +#elif defined _RTW_MP_C_ + #define _MODULE_DEFINE_ _module_mp_ +#elif defined _RTW_MP_IOCTL_C_ + #define _MODULE_DEFINE_ _module_mp_ +#elif defined _RTW_EFUSE_C_ + #define _MODULE_DEFINE_ _module_efuse_ +#endif + +#define DRIVER_PREFIX "RTL8723AU: " +#define DEBUG_LEVEL (_drv_err_) +#define DBG_8723A_LEVEL(_level, fmt, arg...) \ + do { \ + if (_level <= GlobalDebugLevel23A) \ + pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg);\ + } while (0) + +#define DBG_8723A(...) \ + do { \ + if (_drv_err_ <= GlobalDebugLevel23A) \ + pr_info(DRIVER_PREFIX __VA_ARGS__); \ + } while (0) + +#define MSG_8723A(...) \ + do { \ + if (_drv_err_ <= GlobalDebugLevel23A) \ + pr_info(DRIVER_PREFIX __VA_ARGS__); \ + } while (0) + +extern u32 GlobalDebugLevel23A; + + +#define RT_TRACE(_Comp, _Level, Fmt) \ +do { \ + if (_Level <= GlobalDebugLevel23A) { \ + pr_info("%s [0x%08x,%d]", DRIVER_PREFIX, \ + (unsigned int)_Comp, _Level); \ + pr_info Fmt; \ + } \ +} while (0) + +#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, \ + _HexDataLen) \ + if (_Level <= GlobalDebugLevel23A) { \ + int __i; \ + u8 *ptr = (u8 *)_HexData; \ + pr_info("%s", DRIVER_PREFIX); \ + pr_info(_TitleString); \ + for (__i = 0; __i < (int)_HexDataLen; __i++) { \ + printk("%02X%s", ptr[__i], \ + (((__i + 1) % 4) == 0) ? " " : " "); \ + if (((__i + 1) % 16) == 0) \ + printk("\n"); \ + } \ + printk("\n"); \ + } + +#endif /* __RTW_DEBUG_H__ */ diff --git a/drivers/staging/rtl8723au/include/rtw_eeprom.h b/drivers/staging/rtl8723au/include/rtw_eeprom.h new file mode 100644 index 000000000000..d008f032181b --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_eeprom.h @@ -0,0 +1,135 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_EEPROM_H__ +#define __RTW_EEPROM_H__ + +#include +#include + +#define RTL8712_EEPROM_ID 0x8712 +/* define EEPROM_MAX_SIZE 256 */ + +#define HWSET_MAX_SIZE_512 512 +#define EEPROM_MAX_SIZE HWSET_MAX_SIZE_512 + +#define CLOCK_RATE 50 /* 100us */ + +/* EEPROM opcodes */ +#define EEPROM_READ_OPCODE 06 +#define EEPROM_WRITE_OPCODE 05 +#define EEPROM_ERASE_OPCODE 07 +#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ +#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ + +/* Country codes */ +#define USA 0x555320 +#define EUROPE 0x1 /* temp, should be provided later */ +#define JAPAN 0x2 /* temp, should be provided later */ + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_ALPHA 0x1 +#define EEPROM_CID_Senao 0x3 +#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_CAMEO 0X8 +#define EEPROM_CID_SITECOM 0x9 +#define EEPROM_CID_COREGA 0xB +#define EEPROM_CID_EDIMAX_BELKIN 0xC +#define EEPROM_CID_SERCOMM_BELKIN 0xE +#define EEPROM_CID_CAMEO1 0xF +#define EEPROM_CID_WNC_COREGA 0x12 +#define EEPROM_CID_CLEVO 0x13 +#define EEPROM_CID_WHQL 0xFE /* added by chiyoko for dtm, 20090108 */ + +/* */ +/* Customer ID, note that: */ +/* This variable is initiailzed through EEPROM or registry, */ +/* however, its definition may be different with that in EEPROM for */ +/* EEPROM size consideration. So, we have to perform proper translation between them. */ +/* Besides, CustomerID of registry has precedence of that of EEPROM. */ +/* defined below. 060703, by rcnjko. */ +/* */ +enum rt_customer_id +{ + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819x_CAMEO = 6, + RT_CID_819x_RUNTOP = 7, + RT_CID_819x_Senao = 8, + RT_CID_TOSHIBA = 9, /* Merge by Jacken, 2008/01/31. */ + RT_CID_819x_Netcore = 10, + RT_CID_Nettronix = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, + RT_CID_COREGA = 14, + RT_CID_CHINA_MOBILE = 15, + RT_CID_819x_ALPHA = 16, + RT_CID_819x_Sitecom = 17, + RT_CID_CCX = 18, /* It's set under CCX logo test and isn't demanded for CCX functions, but for test behavior like retry limit and tx report. By Bruce, 2009-02-17. */ + RT_CID_819x_Lenovo = 19, + RT_CID_819x_QMI = 20, + RT_CID_819x_Edimax_Belkin = 21, + RT_CID_819x_Sercomm_Belkin = 22, + RT_CID_819x_CAMEO1 = 23, + RT_CID_819x_MSI = 24, + RT_CID_819x_Acer = 25, + RT_CID_819x_AzWave_ASUS = 26, + RT_CID_819x_AzWave = 27, /* For AzWave in PCIe, The ID is AzWave use and not only Asus */ + RT_CID_819x_HP = 28, + RT_CID_819x_WNC_COREGA = 29, + RT_CID_819x_Arcadyan_Belkin = 30, + RT_CID_819x_SAMSUNG = 31, + RT_CID_819x_CLEVO = 32, + RT_CID_819x_DELL = 33, + RT_CID_819x_PRONETS = 34, + RT_CID_819x_Edimax_ASUS = 35, + RT_CID_819x_CAMEO_NETGEAR = 36, + RT_CID_PLANEX = 37, + RT_CID_CC_C = 38, + RT_CID_819x_Xavi = 39, + RT_CID_819x_FUNAI_TV = 40, + RT_CID_819x_ALPHA_WD=41, +}; + +struct eeprom_priv { + u8 bautoload_fail_flag; + u8 bloadfile_fail_flag; + u8 bloadmac_fail_flag; + /* u8 bempty; */ + /* u8 sys_config; */ + u8 mac_addr[6]; /* PermanentAddress */ + /* u8 config0; */ + u16 channel_plan; + /* u8 country_string[3]; */ + /* u8 tx_power_b[15]; */ + /* u8 tx_power_g[15]; */ + /* u8 tx_power_a[201]; */ + + u8 EepromOrEfuse; + + u8 efuse_eeprom_data[HWSET_MAX_SIZE_512]; /* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */ +}; + +void eeprom_write16(struct rtw_adapter *padapter, u16 reg, u16 data); +u16 eeprom_read16(struct rtw_adapter *padapter, u16 reg); +void read_eeprom_content(struct rtw_adapter *padapter); +void eeprom_read_sz(struct rtw_adapter * padapter, u16 reg,u8* data, u32 sz); + +void read_eeprom_content_by_attrib(struct rtw_adapter *padapter); + +#endif /* __RTL871X_EEPROM_H__ */ diff --git a/drivers/staging/rtl8723au/include/rtw_efuse.h b/drivers/staging/rtl8723au/include/rtw_efuse.h new file mode 100644 index 000000000000..a7755056163f --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_efuse.h @@ -0,0 +1,109 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __RTW_EFUSE_H__ +#define __RTW_EFUSE_H__ + +#include + +#define EFUSE_ERROE_HANDLE 1 + +#define PG_STATE_HEADER 0x01 +#define PG_STATE_WORD_0 0x02 +#define PG_STATE_WORD_1 0x04 +#define PG_STATE_WORD_2 0x08 +#define PG_STATE_WORD_3 0x10 +#define PG_STATE_DATA 0x20 + +#define PG_SWBYTE_H 0x01 +#define PG_SWBYTE_L 0x02 + +#define PGPKT_DATA_SIZE 8 + +#define EFUSE_WIFI 0 +#define EFUSE_BT 1 + +enum _EFUSE_DEF_TYPE { + TYPE_EFUSE_MAX_SECTION = 0, + TYPE_EFUSE_REAL_CONTENT_LEN = 1, + TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2, + TYPE_AVAILABLE_EFUSE_BYTES_TOTAL = 3, + TYPE_EFUSE_MAP_LEN = 4, + TYPE_EFUSE_PROTECT_BYTES_BANK = 5, + TYPE_EFUSE_CONTENT_LEN_BANK = 6, +}; + +/* E-Fuse */ +#define EFUSE_MAP_SIZE 256 + +#define EFUSE_MAX_SIZE 512 +/* end of E-Fuse */ + +#define EFUSE_MAX_MAP_LEN 256 +#define EFUSE_MAX_HW_SIZE 512 +#define EFUSE_MAX_SECTION_BASE 16 + +#define EXT_HEADER(header) ((header & 0x1F ) == 0x0F) +#define ALL_WORDS_DISABLED(wde) ((wde & 0x0F) == 0x0F) +#define GET_HDR_OFFSET_2_0(header) ( (header & 0xE0) >> 5) + +#define EFUSE_REPEAT_THRESHOLD_ 3 + +/* */ +/* The following is for BT Efuse definition */ +/* */ +#define EFUSE_BT_MAX_MAP_LEN 1024 +#define EFUSE_MAX_BANK 4 +#define EFUSE_MAX_BT_BANK (EFUSE_MAX_BANK-1) +/* */ +/*--------------------------Define Parameters-------------------------------*/ +#define EFUSE_MAX_WORD_UNIT 4 + +/*------------------------------Define structure----------------------------*/ +struct pg_pkt_struct { + u8 offset; + u8 word_en; + u8 data[8]; + u8 word_cnts; +}; + +/*------------------------Export global variable----------------------------*/ + +u8 efuse_GetCurrentSize23a(struct rtw_adapter *padapter, u16 *size); +u16 efuse_GetMaxSize23a(struct rtw_adapter *padapter); +u8 rtw_efuse_access23a(struct rtw_adapter *padapter, u8 bRead, u16 start_addr, u16 cnts, u8 *data); +u8 rtw_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data); +u8 rtw_efuse_map_write(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data); +u8 rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data); +u8 rtw_BT_efuse_map_write(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data); + +u16 Efuse_GetCurrentSize23a(struct rtw_adapter *pAdapter, u8 efuseType); +u8 Efuse_CalculateWordCnts23a(u8 word_en); +void ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf); +void EFUSE_GetEfuseDefinition23a(struct rtw_adapter *pAdapter, u8 efuseType, u8 type, void *pOut); +u8 efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data); +u8 efuse_OneByteWrite23a(struct rtw_adapter *pAdapter, u16 addr, u8 data); + +void Efuse_PowerSwitch23a(struct rtw_adapter *pAdapter,u8 bWrite,u8 PwrState); +int Efuse_PgPacketRead23a(struct rtw_adapter *pAdapter, u8 offset, u8 *data); +int Efuse_PgPacketWrite23a(struct rtw_adapter *pAdapter, u8 offset, u8 word_en, u8 *data); +void efuse_WordEnableDataRead23a(u8 word_en, u8 *sourdata, u8 *targetdata); +u8 Efuse_WordEnableDataWrite23a(struct rtw_adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data); + +u8 EFUSE_Read1Byte23a(struct rtw_adapter *pAdapter, u16 Address); +void EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType); +void EFUSE_ShadowRead23a(struct rtw_adapter *pAdapter, u8 Type, u16 Offset, u32 *Value); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_event.h b/drivers/staging/rtl8723au/include/rtw_event.h new file mode 100644 index 000000000000..bb20640e6855 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_event.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_EVENT_H_ +#define _RTW_EVENT_H_ + +#include + +#include + +/* +Used to report a bss has been scanned + +*/ +struct survey_event { + struct wlan_bssid_ex bss; +}; + +/* +Used to report that the requested site survey has been done. + +bss_cnt indicates the number of bss that has been reported. + + +*/ +struct surveydone_event { + unsigned int bss_cnt; + +}; + +/* +Used to report the link result of joinning the given bss + + +join_res: +-1: authentication fail +-2: association fail +> 0: TID + +*/ +struct joinbss_event { + struct wlan_network network; +}; + +/* +Used to report a given STA has joinned the created BSS. +It is used in AP/Ad-HoC(M) mode. + + +*/ +struct stassoc_event { + unsigned char macaddr[6]; + unsigned char rsvd[2]; + int cam_id; + +}; + +struct stadel_event { + unsigned char macaddr[6]; + unsigned char rsvd[2]; /* for reason */ + int mac_id; +}; + +struct addba_event +{ + unsigned int tid; +}; + +#define GEN_EVT_CODE(event) event ## _EVT_ + +struct fwevent { + u32 parmsize; + void (*event_callback)(struct rtw_adapter *dev, u8 *pbuf); +}; + + +#define C2HEVENT_SZ 32 + +struct event_node{ + unsigned char *node; + unsigned char evt_code; + unsigned short evt_sz; + volatile int *caller_ff_tail; + int caller_ff_sz; +}; + +struct c2hevent_queue { + volatile int head; + volatile int tail; + struct event_node nodes[C2HEVENT_SZ]; + unsigned char seq; +}; + +#define NETWORK_QUEUE_SZ 4 + +struct network_queue { + volatile int head; + volatile int tail; + struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ]; +}; + + +#endif /* _WLANEVENT_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_ht.h b/drivers/staging/rtl8723au/include/rtw_ht.h new file mode 100644 index 000000000000..7fe0aa46f707 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_ht.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_HT_H_ +#define _RTW_HT_H_ + +#include +#include "linux/ieee80211.h" +#include "wifi.h" + +struct ht_priv +{ + u32 ht_option; + u32 ampdu_enable;/* for enable Tx A-MPDU */ + /* u8 baddbareq_issued[16]; */ + u32 tx_amsdu_enable;/* for enable Tx A-MSDU */ + u32 tx_amdsu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */ + u32 rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, updated when join_callback. */ + + u8 bwmode;/* */ + u8 ch_offset;/* PRIME_CHNL_OFFSET */ + u8 sgi;/* short GI */ + + /* for processing Tx A-MPDU */ + u8 agg_enable_bitmap; + /* u8 ADDBA_retry_count; */ + u8 candidate_tid_bitmap; + + struct ieee80211_ht_cap ht_cap; +}; + +#endif /* _RTL871X_HT_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_io.h b/drivers/staging/rtl8723au/include/rtw_io.h new file mode 100644 index 000000000000..8d39d800267d --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_io.h @@ -0,0 +1,416 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef _RTW_IO_H_ +#define _RTW_IO_H_ + +#include +#include + +#include +#include +#include +/* include */ +#include +#include + +#include +#include + +#define rtw_usb_buffer_alloc(dev, size, dma) usb_alloc_coherent((dev), (size), (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), (dma)) +#define rtw_usb_buffer_free(dev, size, addr, dma) usb_free_coherent((dev), (size), (addr), (dma)) + +#define NUM_IOREQ 8 + +#define MAX_PROT_SZ (64-16) + +#define _IOREADY 0 +#define _IO_WAIT_COMPLETE 1 +#define _IO_WAIT_RSP 2 + +/* IO COMMAND TYPE */ +#define _IOSZ_MASK_ (0x7F) +#define _IO_WRITE_ BIT(7) +#define _IO_FIXED_ BIT(8) +#define _IO_BURST_ BIT(9) +#define _IO_BYTE_ BIT(10) +#define _IO_HW_ BIT(11) +#define _IO_WORD_ BIT(12) +#define _IO_SYNC_ BIT(13) +#define _IO_CMDMASK_ (0x1F80) + + +/* + For prompt mode accessing, caller shall free io_req + Otherwise, io_handler will free io_req +*/ + + + +/* IO STATUS TYPE */ +#define _IO_ERR_ BIT(2) +#define _IO_SUCCESS_ BIT(1) +#define _IO_DONE_ BIT(0) + + +#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) +#define IO_RD16 (_IO_SYNC_ | _IO_HW_) +#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) + +#define IO_RD32_ASYNC (_IO_WORD_) +#define IO_RD16_ASYNC (_IO_HW_) +#define IO_RD8_ASYNC (_IO_BYTE_) + +#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) +#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) +#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) + +#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) +#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) +#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) + +/* + + Only Sync. burst accessing is provided. + +*/ + +#define IO_WR_BURST(x) (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_)) +#define IO_RD_BURST(x) (_IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_)) + + + +/* below is for the intf_option bit defition... */ + +#define _INTF_ASYNC_ BIT(0) /* support async io */ + +struct intf_priv; +struct intf_hdl; +struct io_queue; + +struct _io_ops +{ + u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); + u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); + u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); + + int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); + + int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + + void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + + void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); + + u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr); + + u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct recv_buf *rbuf); + u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct xmit_buf *pmem); + + u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem); + + void (*_read_port_cancel)(struct intf_hdl *pintfhdl); + void (*_write_port_cancel)(struct intf_hdl *pintfhdl); + +}; + +struct io_req { + struct list_head list; + u32 addr; + volatile u32 val; + u32 command; + u32 status; + u8 *pbuf; + struct semaphore sema; + + void (*_async_io_callback)(struct rtw_adapter *padater, struct io_req *pio_req, u8 *cnxt); + u8 *cnxt; +}; + +struct intf_hdl { + struct rtw_adapter *padapter; + struct dvobj_priv *pintf_dev;/* pointer to &(padapter->dvobjpriv); */ + + struct _io_ops io_ops; + +}; + +struct reg_protocol_rd { + +#ifdef __LITTLE_ENDIAN + + /* DW1 */ + u32 NumOfTrans:4; + u32 Reserved1:4; + u32 Reserved2:24; + /* DW2 */ + u32 ByteCount:7; + u32 WriteEnable:1; /* 0:read, 1:write */ + u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ + u32 BurstMode:1; + u32 Byte1Access:1; + u32 Byte2Access:1; + u32 Byte4Access:1; + u32 Reserved3:3; + u32 Reserved4:16; + /* DW3 */ + u32 BusAddress; + /* DW4 */ + /* u32 Value; */ +#else + + +/* DW1 */ + u32 Reserved1 :4; + u32 NumOfTrans :4; + + u32 Reserved2 :24; + + /* DW2 */ + u32 WriteEnable : 1; + u32 ByteCount :7; + + + u32 Reserved3 : 3; + u32 Byte4Access : 1; + + u32 Byte2Access : 1; + u32 Byte1Access : 1; + u32 BurstMode :1 ; + u32 FixOrContinuous : 1; + + u32 Reserved4 : 16; + + /* DW3 */ + u32 BusAddress; + + /* DW4 */ + /* u32 Value; */ + +#endif + +}; + + +struct reg_protocol_wt { + + +#ifdef __LITTLE_ENDIAN + + /* DW1 */ + u32 NumOfTrans:4; + u32 Reserved1:4; + u32 Reserved2:24; + /* DW2 */ + u32 ByteCount:7; + u32 WriteEnable:1; /* 0:read, 1:write */ + u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ + u32 BurstMode:1; + u32 Byte1Access:1; + u32 Byte2Access:1; + u32 Byte4Access:1; + u32 Reserved3:3; + u32 Reserved4:16; + /* DW3 */ + u32 BusAddress; + /* DW4 */ + u32 Value; + +#else + /* DW1 */ + u32 Reserved1 :4; + u32 NumOfTrans :4; + + u32 Reserved2 :24; + + /* DW2 */ + u32 WriteEnable : 1; + u32 ByteCount :7; + + u32 Reserved3 : 3; + u32 Byte4Access : 1; + + u32 Byte2Access : 1; + u32 Byte1Access : 1; + u32 BurstMode :1 ; + u32 FixOrContinuous : 1; + + u32 Reserved4 : 16; + + /* DW3 */ + u32 BusAddress; + + /* DW4 */ + u32 Value; + +#endif + +}; + + + +/* +Below is the data structure used by _io_handler + +*/ + +struct io_queue { + spinlock_t lock; + struct list_head free_ioreqs; + struct list_head pending; /* The io_req list that will be served in the single protocol read/write. */ + struct list_head processing; + u8 *free_ioreqs_buf; /* 4-byte aligned */ + u8 *pallocated_free_ioreqs_buf; + struct intf_hdl intf; +}; + +struct io_priv{ + + struct rtw_adapter *padapter; + + struct intf_hdl intf; + +}; + +uint ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue); +void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue); +uint sync_ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue); + +uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue); +struct io_req *alloc_ioreq(struct io_queue *pio_q); + +uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl); +void unregister_intf_hdl(struct intf_hdl *pintfhdl); + +void _rtw_attrib_read(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +void _rtw_attrib_write(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); + +u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr); +u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr); +u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr); +void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct recv_buf *rbuf); +void _rtw_read_port23a_cancel(struct rtw_adapter *adapter); + +int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val); +int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val); +int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val); +int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr, u32 length, u8 *pdata); + +int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val); +int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val); +int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val); + +void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem); +u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem); +u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem, int timeout_ms); +void _rtw_write_port23a_cancel(struct rtw_adapter *adapter); + +#ifdef DBG_IO +bool match_read_sniff_ranges(u16 addr, u16 len); +bool match_write_sniff_ranges(u16 addr, u16 len); + +u8 dbg_rtw_read823a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line); +u16 dbg_rtw_read1623a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line); +u32 dbg_rtw_read3223a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line); + +int dbg_rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val, const char *caller, const int line); +int dbg_rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val, const char *caller, const int line); +int dbg_rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val, const char *caller, const int line); +int dbg_rtw_writeN23a(struct rtw_adapter *adapter, u32 addr ,u32 length , u8 *data, const char *caller, const int line); + +#define rtw_read8(adapter, addr) dbg_rtw_read823a((adapter), (addr), __FUNCTION__, __LINE__) +#define rtw_read16(adapter, addr) dbg_rtw_read1623a((adapter), (addr), __FUNCTION__, __LINE__) +#define rtw_read32(adapter, addr) dbg_rtw_read3223a((adapter), (addr), __FUNCTION__, __LINE__) +#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem23a((adapter), (addr), (cnt), (mem)) +#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port23a((adapter), (addr), (cnt), (mem)) +#define rtw_read_port_cancel(adapter) _rtw_read_port23a_cancel((adapter)) + +#define rtw_write8(adapter, addr, val) dbg_rtw_write823a((adapter), (addr), (val), __FUNCTION__, __LINE__) +#define rtw_write16(adapter, addr, val) dbg_rtw_write1623a((adapter), (addr), (val), __FUNCTION__, __LINE__) +#define rtw_write32(adapter, addr, val) dbg_rtw_write3223a((adapter), (addr), (val), __FUNCTION__, __LINE__) +#define rtw_writeN(adapter, addr, length, data) dbg_rtw_writeN23a((adapter), (addr), (length), (data), __FUNCTION__, __LINE__) + +#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val)) +#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val)) +#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val)) + +#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), addr, cnt, mem) +#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a(adapter, addr, cnt, mem) +#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms)) +#define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel(adapter) +#else /* DBG_IO */ +#define rtw_read8(adapter, addr) _rtw_read823a((adapter), (addr)) +#define rtw_read16(adapter, addr) _rtw_read1623a((adapter), (addr)) +#define rtw_read32(adapter, addr) _rtw_read3223a((adapter), (addr)) +#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem23a((adapter), (addr), (cnt), (mem)) +#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port23a((adapter), (addr), (cnt), (mem)) +#define rtw_read_port_cancel(adapter) _rtw_read_port23a_cancel((adapter)) + +#define rtw_write8(adapter, addr, val) _rtw_write823a((adapter), (addr), (val)) +#define rtw_write16(adapter, addr, val) _rtw_write1623a((adapter), (addr), (val)) +#define rtw_write32(adapter, addr, val) _rtw_write3223a((adapter), (addr), (val)) +#define rtw_writeN(adapter, addr, length, data) _rtw_writeN23a((adapter), (addr), (length), (data)) + +#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val)) +#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val)) +#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val)) + +#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), (addr), (cnt), (mem)) +#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a((adapter), (addr), (cnt), (mem)) +#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms)) +#define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel((adapter)) +#endif /* DBG_IO */ + +void rtw_write_scsi(struct rtw_adapter *adapter, u32 cnt, u8 *pmem); + +/* ioreq */ +void ioreq_read8(struct rtw_adapter *adapter, u32 addr, u8 *pval); +void ioreq_read16(struct rtw_adapter *adapter, u32 addr, u16 *pval); +void ioreq_read32(struct rtw_adapter *adapter, u32 addr, u32 *pval); +void ioreq_write8(struct rtw_adapter *adapter, u32 addr, u8 val); +void ioreq_write16(struct rtw_adapter *adapter, u32 addr, u16 val); +void ioreq_write32(struct rtw_adapter *adapter, u32 addr, u32 val); + +int rtw_init_io_priv23a(struct rtw_adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)); + +uint alloc_io_queue(struct rtw_adapter *adapter); +void free_io_queue(struct rtw_adapter *adapter); +void async_bus_io(struct io_queue *pio_q); +void bus_sync_io(struct io_queue *pio_q); +u32 _ioreq2rwmem(struct io_queue *pio_q); +void dev_power_down(struct rtw_adapter * Adapter, u8 bpwrup); + +#define PlatformEFIOWrite1Byte(_a,_b,_c) \ + rtw_write8(_a,_b,_c) +#define PlatformEFIOWrite2Byte(_a,_b,_c) \ + rtw_write16(_a,_b,_c) +#define PlatformEFIOWrite4Byte(_a,_b,_c) \ + rtw_write32(_a,_b,_c) + +#define PlatformEFIORead1Byte(_a,_b) \ + rtw_read8(_a,_b) +#define PlatformEFIORead2Byte(_a,_b) \ + rtw_read16(_a,_b) +#define PlatformEFIORead4Byte(_a,_b) \ + rtw_read32(_a,_b) + +#endif /* _RTL8711_IO_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_ioctl.h b/drivers/staging/rtl8723au/include/rtw_ioctl.h new file mode 100644 index 000000000000..629eec8a7023 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_ioctl.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_IOCTL_H_ +#define _RTW_IOCTL_H_ + +#include +#include + + +#if defined(CONFIG_WIRELESS_EXT) +extern struct iw_handler_def rtw_handlers_def; +#endif + +#endif /* #ifndef __INC_CEINFO_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_ioctl_set.h b/drivers/staging/rtl8723au/include/rtw_ioctl_set.h new file mode 100644 index 000000000000..18ad2a873350 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_ioctl_set.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_IOCTL_SET_H_ +#define __RTW_IOCTL_SET_H_ + +#include + + +struct bssid_info { + unsigned char BSSID[6]; + u8 PMKID[16]; +}; + +u8 rtw_set_802_11_authentication_mode23a(struct rtw_adapter *pdapter, + enum ndis_802_11_auth_mode authmode); +u8 rtw_set_802_11_add_wep23a(struct rtw_adapter * padapter, + struct ndis_802_11_wep *wep); +u8 rtw_set_802_11_bssid23a_list_scan(struct rtw_adapter *padapter, + struct cfg80211_ssid *pssid, int ssid_max_num); +u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter *padapter, + enum ndis_802_11_net_infra networktype); +u8 rtw_set_802_11_ssid23a(struct rtw_adapter * padapter, struct cfg80211_ssid * ssid); + +u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter); +s32 FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_led.h b/drivers/staging/rtl8723au/include/rtw_led.h new file mode 100644 index 000000000000..c071da587efd --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_led.h @@ -0,0 +1,181 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_LED_H_ +#define __RTW_LED_H_ + +#include +#include + +#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) + +#define LED_BLINK_NORMAL_INTERVAL 100 +#define LED_BLINK_SLOWLY_INTERVAL 200 +#define LED_BLINK_LONG_INTERVAL 400 + +#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 +#define LED_BLINK_LINK_INTERVAL_ALPHA 500 /* 500 */ +#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 /* 150 */ +#define LED_BLINK_FASTER_INTERVAL_ALPHA 50 +#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000 + +#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX 100 +#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX 2000 + +#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000 +#define LED_BLINK_NORMAL_INTERVAL_PORNET 100 + +#define LED_BLINK_FAST_INTERVAL_BITLAND 30 + +/* 060403, rcnjko: Customized for AzWave. */ +#define LED_CM2_BLINK_ON_INTERVAL 250 +#define LED_CM2_BLINK_OFF_INTERVAL 4750 + +#define LED_CM8_BLINK_INTERVAL 500 /* for QMI */ +#define LED_CM8_BLINK_OFF_INTERVAL 3750 /* for QMI */ + +/* 080124, lanhsin: Customized for RunTop */ +#define LED_RunTop_BLINK_INTERVAL 300 + +/* 060421, rcnjko: Customized for Sercomm Printer Server case. */ +#define LED_CM3_BLINK_INTERVAL 1500 + +enum led_ctl_mode { + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, + LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */ + LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */ + LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */ + LED_CTL_CONNECTION_NO_TRANSFER = 14, +}; + +enum led_state_872x { + LED_UNKNOWN = 0, + RTW_LED_ON = 1, + RTW_LED_OFF = 2, + LED_BLINK_NORMAL = 3, + LED_BLINK_SLOWLY = 4, + LED_BLINK_POWER_ON = 5, + LED_BLINK_SCAN = 6, /* LED is blinking during scanning period, the # of times to blink is depend on time for scanning. */ + LED_BLINK_NO_LINK = 7, /* LED is blinking during no link state. */ + LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer Server case */ + LED_BLINK_TXRX = 9, + LED_BLINK_WPS = 10, /* LED is blinkg during WPS communication */ + LED_BLINK_WPS_STOP = 11, /* for ALPHA */ + LED_BLINK_WPS_STOP_OVERLAP = 12, /* for BELKIN */ + LED_BLINK_RUNTOP = 13, /* Customized for RunTop */ + LED_BLINK_CAMEO = 14, + LED_BLINK_XAVI = 15, + LED_BLINK_ALWAYS_ON = 16, +}; + +enum led_pin_8723a { + LED_PIN_NULL = 0, + LED_PIN_LED0 = 1, + LED_PIN_LED1 = 2, + LED_PIN_LED2 = 3, + LED_PIN_GPIO0 = 4, +}; + +struct led_8723a { + struct rtw_adapter *padapter; + + enum led_pin_8723a LedPin; /* Identify how to implement this SW led. */ + enum led_state_872x CurrLedState; /* Current LED state. */ + enum led_state_872x BlinkingLedState; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */ + + u8 bLedOn; /* true if LED is ON, false if LED is OFF. */ + + u8 bLedBlinkInProgress; /* true if it is blinking, false o.w.. */ + + u8 bLedWPSBlinkInProgress; + + u32 BlinkTimes; /* Number of times to toggle led state for blinking. */ + + struct timer_list BlinkTimer; /* Timer object for led blinking. */ + + u8 bSWLedCtrl; + + /* ALPHA, added by chiyoko, 20090106 */ + u8 bLedNoLinkBlinkInProgress; + u8 bLedLinkBlinkInProgress; + u8 bLedStartToLinkBlinkInProgress; + u8 bLedScanBlinkInProgress; + + struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer to manipulate H/W to blink LED. */ +}; + +#define IS_LED_WPS_BLINKING(_LED_871x) (((struct led_8723a *)_LED_871x)->CurrLedState==LED_BLINK_WPS \ + || ((struct led_8723a *)_LED_871x)->CurrLedState==LED_BLINK_WPS_STOP \ + || ((struct led_8723a *)_LED_871x)->bLedWPSBlinkInProgress) + +#define IS_LED_BLINKING(_LED_871x) (((struct led_8723a *)_LED_871x)->bLedWPSBlinkInProgress \ + ||((struct led_8723a *)_LED_871x)->bLedScanBlinkInProgress) + +/* */ +/* LED customization. */ +/* */ + +enum led_strategy_8723a { + SW_LED_MODE0 = 0, /* SW control 1 LED via GPIO0. It is default option. */ + SW_LED_MODE1= 1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */ + SW_LED_MODE2 = 2, /* SW control 1 LED via GPIO0, customized for AzWave 8187 minicard. */ + SW_LED_MODE3 = 3, /* SW control 1 LED via GPIO0, customized for Sercomm Printer Server case. */ + SW_LED_MODE4 = 4, /* for Edimax / Belkin */ + SW_LED_MODE5 = 5, /* for Sercomm / Belkin */ + SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */ + HW_LED = 50, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes, see MAC.CONFIG1 for details.) */ + LED_ST_NONE = 99, +}; + +void LedControl871x23a(struct rtw_adapter *padapter, enum led_ctl_mode LedAction); + +struct led_priv{ + /* add for led controll */ + struct led_8723a SwLed0; + struct led_8723a SwLed1; + enum led_strategy_8723a LedStrategy; + u8 bRegUseLed; + void (*LedControlHandler)(struct rtw_adapter *padapter, enum led_ctl_mode LedAction); + /* add for led controll */ +}; + +#define rtw_led_control(adapter, LedAction) + +void BlinkWorkItemCallback23a(struct work_struct *work); + +void ResetLedStatus23a(struct led_8723a *pLed); + +void +InitLed871x23a( + struct rtw_adapter *padapter, + struct led_8723a *pLed, + enum led_pin_8723a LedPin +); + +void +DeInitLed871x23a(struct led_8723a *pLed); + +/* hal... */ +void BlinkHandler23a(struct led_8723a *pLed); + +#endif /* __RTW_LED_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_mlme.h b/drivers/staging/rtl8723au/include/rtw_mlme.h new file mode 100644 index 000000000000..adbea44d601f --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_mlme.h @@ -0,0 +1,632 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + * + ******************************************************************************/ +#ifndef __RTW_MLME_H_ +#define __RTW_MLME_H_ + +#include +#include +#include +#include + +#define MAX_BSS_CNT 128 +#define MAX_JOIN_TIMEOUT 6500 + +/* Increase the scanning timeout because of increasing the SURVEY_TO value. */ + +#define SCANNING_TIMEOUT 8000 + +#define SCAN_INTERVAL (30) /* unit:2sec, 30*2 = 60sec */ + +#define SCANQUEUE_LIFETIME 20 /* unit:sec */ + +#define WIFI_NULL_STATE 0x00000000 + +#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state.*/ +#define WIFI_REASOC_STATE 0x00000002 +#define WIFI_SLEEP_STATE 0x00000004 +#define WIFI_STATION_STATE 0x00000008 + +#define WIFI_AP_STATE 0x00000010 +#define WIFI_ADHOC_STATE 0x00000020 +#define WIFI_ADHOC_MASTER_STATE 0x00000040 +#define WIFI_UNDER_LINKING 0x00000080 + +#define WIFI_UNDER_WPS 0x00000100 +#define WIFI_STA_ALIVE_CHK_STATE 0x00000400 +/* to indicate the station is under site surveying */ +#define WIFI_SITE_MONITOR 0x00000800 + +#define WIFI_MP_STATE 0x00010000 +#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continous tx background */ +#define WIFI_MP_CTX_ST 0x00040000 /* in continous tx with single-tone */ +#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continous tx background due to out of skb */ +#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx */ +#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continous tx with carrier suppression */ +#define WIFI_MP_LPBK_STATE 0x00400000 + +#define _FW_UNDER_LINKING WIFI_UNDER_LINKING +#define _FW_LINKED WIFI_ASOC_STATE +#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR + + +enum dot11AuthAlgrthmNum { + dot11AuthAlgrthm_Open = 0, + dot11AuthAlgrthm_Shared, + dot11AuthAlgrthm_8021X, + dot11AuthAlgrthm_Auto, + dot11AuthAlgrthm_MaxNum +}; + +/* Scan type including active and passive scan. */ +enum rt_scan_type { + SCAN_PASSIVE, + SCAN_ACTIVE, + SCAN_MIX, +}; + +enum { + GHZ24_50 = 0, + GHZ_50, + GHZ_24, +}; + +enum SCAN_RESULT_TYPE { + SCAN_RESULT_P2P_ONLY = 0, /* Will return all the P2P devices. */ + SCAN_RESULT_ALL = 1, /* Will return all the scanned device, include AP. */ + SCAN_RESULT_WFD_TYPE = 2 /* Will just return the correct WFD device. */ + /* If this device is Miracast sink device, it will just return all the Miracast source devices. */ +}; + +/* + +there are several "locks" in mlme_priv, +since mlme_priv is a shared resource between many threads, +like ISR/Call-Back functions, the OID handlers, and even timer functions. + + +Each _queue has its own locks, already. +Other items are protected by mlme_priv.lock. + +To avoid possible dead lock, any thread trying to modifiying mlme_priv +SHALL not lock up more than one locks at a time! +*/ + +#define traffic_threshold 10 +#define traffic_scan_period 500 + +struct sitesurvey_ctrl { + u64 last_tx_pkts; + uint last_rx_pkts; + int traffic_busy; + struct timer_list sitesurvey_ctrl_timer; +}; + +struct rt_link_detect { + u32 NumTxOkInPeriod; + u32 NumRxOkInPeriod; + u32 NumRxUnicastOkInPeriod; + bool bBusyTraffic; + bool bTxBusyTraffic; + bool bRxBusyTraffic; + bool bHigherBusyTraffic; /* For interrupt migration purpose. */ + bool bHigherBusyRxTraffic; /* We may disable Tx interrupt according as Rx traffic. */ + bool bHigherBusyTxTraffic; /* We may disable Tx interrupt according as Tx traffic. */ +}; + +struct profile_info { + u8 ssidlen; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 peermac[ETH_ALEN]; +}; + +struct tx_invite_req_info { + u8 token; + u8 benable; + u8 go_ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssidlen; + u8 go_bssid[ETH_ALEN]; + u8 peer_macaddr[ETH_ALEN]; + u8 operating_ch; /* This information will be set by using the p2p_set op_ch = x */ + u8 peer_ch; /* The listen channel for peer P2P device */ + +}; + +struct tx_invite_resp_info { + u8 token; /* Used to record the dialog token of p2p invitation request frame. */ +}; + +#ifdef CONFIG_8723AU_P2P + +struct wifi_display_info { + u16 wfd_enable; /* Enable/Disable the WFD function. */ + u16 rtsp_ctrlport; /* TCP port number at which the this WFD device listens for RTSP messages */ + u16 peer_rtsp_ctrlport; /* TCP port number at which the peer WFD device listens for RTSP messages */ + /* This filed should be filled when receiving the gropu negotiation request */ + + u8 peer_session_avail; /* WFD session is available or not for the peer wfd device. */ + /* This variable will be set when sending the provisioning discovery request to peer WFD device. */ + /* And this variable will be reset when it is read by using the iwpriv p2p_get wfd_sa command. */ + u8 ip_address[4]; + u8 peer_ip_address[4]; + u8 wfd_pc; /* WFD preferred connection */ + /* 0 -> Prefer to use the P2P for WFD connection on peer side. */ + /* 1 -> Prefer to use the TDLS for WFD connection on peer side. */ + + u8 wfd_device_type;/* WFD Device Type */ + /* 0 -> WFD Source Device */ + /* 1 -> WFD Primary Sink Device */ + enum SCAN_RESULT_TYPE scan_result_type; /* Used when P2P is enable. This parameter will impact the scan result. */ +}; +#endif /* CONFIG_8723AU_P2P */ + +struct tx_provdisc_req_info { + u16 wps_config_method_request; /* Used when sending the provisioning request frame */ + u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ + struct cfg80211_ssid ssid; + u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ + u8 peerIFAddr[ETH_ALEN]; /* Peer interface address */ + u8 benable; /* This provision discovery request frame is trigger to send or not */ +}; + +struct rx_provdisc_req_info { /* When peer device issue prov_disc_req first, we should store the following informations */ + u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ + u8 strconfig_method_desc_of_prov_disc_req[4]; /* description for the config method located in the provisioning discovery request frame. */ + /* The UI must know this information to know which config method the remote p2p device is requiring. */ +}; + +struct tx_nego_req_info { + u16 peer_channel_num[2]; /* The channel number which the receiver stands. */ + u8 peerDevAddr[ETH_ALEN];/* Peer device address */ + u8 benable; /* This negoitation request frame is trigger to send or not */ +}; + +struct group_id_info { + u8 go_device_addr[ETH_ALEN]; /*The GO's device address of P2P group */ + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* The SSID of this P2P group */ +}; + +struct scan_limit_info { + u8 scan_op_ch_only; /* When this flag is set, the driver should just scan the operation channel */ + u8 operation_ch[2]; /* Store the operation channel of invitation request frame */ +}; + +struct cfg80211_wifidirect_info { + struct timer_list remain_on_ch_timer; + u8 restore_channel; + struct ieee80211_channel remain_on_ch_channel; + enum nl80211_channel_type remain_on_ch_type; + u64 remain_on_ch_cookie; + bool is_ro_ch; +}; + +struct wifidirect_info { + struct rtw_adapter *padapter; + struct timer_list find_phase_timer; + struct timer_list restore_p2p_state_timer; + + /* Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. */ + struct timer_list pre_tx_scan_timer; + struct timer_list reset_ch_sitesurvey; + struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan limit function by using p2p nego */ + struct tx_provdisc_req_info tx_prov_disc_info; + struct rx_provdisc_req_info rx_prov_disc_info; + struct tx_invite_req_info invitereq_info; + struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM]; /* Store the profile information of persistent group */ + struct tx_invite_resp_info inviteresp_info; + struct tx_nego_req_info nego_req_info; + struct group_id_info groupid_info; /* Store the group id information when doing the group negotiation handshake. */ + struct scan_limit_info rx_invitereq_info; /* Used for get the limit scan channel from the Invitation procedure */ + struct scan_limit_info p2p_info; /* Used for get the limit scan channel from the P2P negotiation handshake */ +#ifdef CONFIG_8723AU_P2P + struct wifi_display_info *wfd_info; +#endif + enum P2P_ROLE role; + enum P2P_STATE pre_p2p_state; + enum P2P_STATE p2p_state; + u8 device_addr[ETH_ALEN]; /* The device address should be the mac address of this device. */ + u8 interface_addr[ETH_ALEN]; + u8 social_chan[4]; + u8 listen_channel; + u8 operating_channel; + u8 listen_dwell; /* This value should be between 1 and 3 */ + u8 support_rate[8]; + u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN]; + u8 intent; /* should only include the intent value. */ + u8 p2p_peer_interface_addr[ETH_ALEN]; + u8 p2p_peer_device_addr[ETH_ALEN]; + u8 peer_intent; /* Included the intent value and tie breaker value. */ + u8 device_name[WPS_MAX_DEVICE_NAME_LEN]; /* Device name for displaying on searching device screen */ + u8 device_name_len; + u8 profileindex; /* Used to point to the index of profileinfo array */ + u8 peer_operating_ch; + u8 find_phase_state_exchange_cnt; + u16 device_password_id_for_nego; /* The device password ID for group negotation */ + u8 negotiation_dialog_token; + /* SSID information for group negotitation */ + u8 nego_ssid[IEEE80211_MAX_SSID_LEN]; + u8 nego_ssidlen; + u8 p2p_group_ssid[IEEE80211_MAX_SSID_LEN]; + u8 p2p_group_ssid_len; + u8 persistent_supported; /* Flag to know the persistent function should be supported or not. */ + /* In the Sigma test, the Sigma will provide this enable from the sta_set_p2p CAPI. */ + /* 0: disable */ + /* 1: enable */ + u8 session_available; /* Flag to set the WFD session available to enable or disable "by Sigma" */ + /* In the Sigma test, the Sigma will disable the session available by using the sta_preset CAPI. */ + /* 0: disable */ + /* 1: enable */ + + u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma */ + /* 0: disable */ + /* 1: enable */ + u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security function for TDLS by WFD Sigma */ + /* 0: disable */ + /* In this case, the driver can't issue the tdsl setup request frame. */ + /* 1: enable */ + /* In this case, the driver can issue the tdls setup request frame */ + /* even the current security is weak security. */ + + enum P2P_WPSINFO ui_got_wps_info; /* This field will store the WPS value (PIN value or PBC) that UI had got from the user. */ + u16 supported_wps_cm; /* This field describes the WPS config method which this driver supported. */ + /* The value should be the combination of config method defined in page104 of WPS v2.0 spec. */ + uint channel_list_attr_len; /* This field will contain the length of body of P2P Channel List attribute of group negotitation response frame. */ + u8 channel_list_attr[100]; /* This field will contain the body of P2P Channel List attribute of group negotitation response frame. */ + /* We will use the channel_cnt and channel_list fields when constructing the group negotitation confirm frame. */ +#ifdef CONFIG_8723AU_P2P + enum P2P_PS_MODE p2p_ps_mode; /* indicate p2p ps mode */ + enum P2P_PS_STATE p2p_ps_state; /* indicate p2p ps state */ + u8 noa_index; /* Identifies and instance of Notice of Absence timing. */ + u8 ctwindow; /* Client traffic window. A period of time in TU after TBTT. */ + u8 opp_ps; /* opportunistic power save. */ + u8 noa_num; /* number of NoA descriptor in P2P IE. */ + u8 noa_count[P2P_MAX_NOA_NUM]; /* Count for owner, Type of client. */ + u32 noa_duration[P2P_MAX_NOA_NUM]; /* Max duration for owner, preferred or min acceptable duration for client. */ + u32 noa_interval[P2P_MAX_NOA_NUM]; /* Length of interval for owner, preferred or max acceptable interval of client. */ + u32 noa_start_time[P2P_MAX_NOA_NUM]; /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */ +#endif /* CONFIG_8723AU_P2P */ +}; + +struct tdls_ss_record { /* signal strength record */ + u8 macaddr[ETH_ALEN]; + u8 RxPWDBAll; + u8 is_tdls_sta; /* true: direct link sta, false: else */ +}; + +struct tdls_info { + u8 ap_prohibited; + uint setup_state; + u8 sta_cnt; + /* 1:tdls sta == (NUM_STA-1), reach max direct link no; 0: else; */ + u8 sta_maximum; + struct tdls_ss_record ss_record; + u8 macid_index; /* macid entry that is ready to write */ + /* cam entry that is trying to clear, using it in direct link teardown*/ + u8 clear_cam; + u8 ch_sensing; + u8 cur_channel; + u8 candidate_ch; + u8 collect_pkt_num[MAX_CHANNEL_NUM]; + spinlock_t cmd_lock; + spinlock_t hdl_lock; + u8 watchdog_count; + u8 dev_discovered; /* WFD_TDLS: for sigma test */ + u8 enable; +#ifdef CONFIG_8723AU_P2P + struct wifi_display_info *wfd_info; +#endif +}; + +struct mlme_priv { + spinlock_t lock; + int fw_state; + u8 bScanInProcess; + u8 to_join; /* flag */ + u8 to_roaming; /* roaming trying times */ + + struct rtw_adapter *nic_hdl; + + u8 not_indic_disco; + struct rtw_queue scanned_queue; + + struct cfg80211_ssid assoc_ssid; + u8 assoc_bssid[6]; + + struct wlan_network cur_network; + + /* uint wireless_mode; no used, remove it */ + + u32 scan_interval; + + struct timer_list assoc_timer; + + uint assoc_by_bssid; + uint assoc_by_rssi; + + struct timer_list scan_to_timer; + + struct timer_list set_scan_deny_timer; + atomic_t set_scan_deny; /* 0: allowed, 1: deny */ + + struct qos_priv qospriv; + + /* Number of non-HT AP/stations */ + int num_sta_no_ht; + + int num_FortyMHzIntolerant; + + struct ht_priv htpriv; + + struct rt_link_detect LinkDetectInfo; + struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */ + + u8 key_mask; /* use for ips to set wep key after ips_leave23a */ + u8 acm_mask; /* for wmm acm mask */ + u8 ChannelPlan; + enum rt_scan_type scan_mode; /* active: 1, passive: 0 */ + + u8 *wps_probe_req_ie; + u32 wps_probe_req_ie_len; + +#ifdef CONFIG_8723AU_AP_MODE + /* Number of associated Non-ERP stations (i.e., stations using 802.11b + * in 802.11g BSS) */ + int num_sta_non_erp; + + /* Number of associated stations that do not support Short Slot Time */ + int num_sta_no_short_slot_time; + + /* Number of associated stations that do not support Short Preamble */ + int num_sta_no_short_preamble; + + int olbc; /* Overlapping Legacy BSS Condition */ + + /* Number of HT associated stations that do not support greenfield */ + int num_sta_ht_no_gf; + + /* Number of associated non-HT stations */ + /* int num_sta_no_ht; */ + + /* Number of HT associated stations 20 MHz */ + int num_sta_ht_20mhz; + + /* Overlapping BSS information */ + int olbc_ht; + + u16 ht_op_mode; + + u8 *assoc_req; + u32 assoc_req_len; + u8 *assoc_rsp; + u32 assoc_rsp_len; + + u8 *wps_beacon_ie; + /* u8 *wps_probe_req_ie; */ + u8 *wps_probe_resp_ie; + u8 *wps_assoc_resp_ie; + + u32 wps_beacon_ie_len; + /* u32 wps_probe_req_ie_len; */ + u32 wps_probe_resp_ie_len; + u32 wps_assoc_resp_ie_len; + + u8 *p2p_beacon_ie; + u8 *p2p_probe_req_ie; + u8 *p2p_probe_resp_ie; + u8 *p2p_go_probe_resp_ie; /* for GO */ + u8 *p2p_assoc_req_ie; + + u32 p2p_beacon_ie_len; + u32 p2p_probe_req_ie_len; + u32 p2p_probe_resp_ie_len; + u32 p2p_go_probe_resp_ie_len; /* for GO */ + u32 p2p_assoc_req_ie_len; + spinlock_t bcn_update_lock; + u8 update_bcn; + +#endif /* ifdef CONFIG_8723AU_AP_MODE */ + +#if defined(CONFIG_8723AU_P2P) + u8 *wfd_beacon_ie; + u8 *wfd_probe_req_ie; + u8 *wfd_probe_resp_ie; + u8 *wfd_go_probe_resp_ie; /* for GO */ + u8 *wfd_assoc_req_ie; + + u32 wfd_beacon_ie_len; + u32 wfd_probe_req_ie_len; + u32 wfd_probe_resp_ie_len; + u32 wfd_go_probe_resp_ie_len; /* for GO */ + u32 wfd_assoc_req_ie_len; +#endif +}; + +#ifdef CONFIG_8723AU_AP_MODE + +struct hostapd_priv { + struct rtw_adapter *padapter; +}; + +int hostapd_mode_init(struct rtw_adapter *padapter); +void hostapd_mode_unload(struct rtw_adapter *padapter); +#endif + +void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); +void rtw_cpwm_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf); + + +int event_thread(void *context); +void rtw23a_join_to_handler(unsigned long); + +void rtw_free_network_queue23a(struct rtw_adapter *adapter, u8 isfreeall); +int rtw_init_mlme_priv23a(struct rtw_adapter *adapter); + +void rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv); + +int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv); +int rtw_set_key23a(struct rtw_adapter *adapter, + struct security_priv *psecuritypriv, int keyid, u8 set_tx); +int rtw_set_auth23a(struct rtw_adapter *adapter, + struct security_priv *psecuritypriv); + +static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) +{ /* if sta_mode:pmlmepriv->cur_network.network.MacAddress => bssid */ + /* if adhoc_mode:pmlmepriv->cur_network.network.MacAddress => ibss mac address */ + return pmlmepriv->cur_network.network.MacAddress; +} + +static inline int check_fwstate(struct mlme_priv *pmlmepriv, int state) +{ + if (pmlmepriv->fw_state & state) + return true; + + return false; +} + +static inline int get_fwstate(struct mlme_priv *pmlmepriv) +{ + return pmlmepriv->fw_state; +} + +/* + * No Limit on the calling context, + * therefore set it to be the critical section... + * + * ### NOTE:#### (!!!!) + * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock + */ +static inline void set_fwstate(struct mlme_priv *pmlmepriv, int state) +{ + pmlmepriv->fw_state |= state; + /* FOR HW integration */ + if (_FW_UNDER_SURVEY == state) + pmlmepriv->bScanInProcess = true; +} + +static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, int state) +{ + pmlmepriv->fw_state &= ~state; + /* FOR HW integration */ + if (_FW_UNDER_SURVEY == state) + pmlmepriv->bScanInProcess = false; +} + +/* + * No Limit on the calling context, + * therefore set it to be the critical section... + */ +static inline void clr_fwstate(struct mlme_priv *pmlmepriv, int state) +{ + spin_lock_bh(&pmlmepriv->lock); + if (check_fwstate(pmlmepriv, state) == true) + pmlmepriv->fw_state ^= state; + spin_unlock_bh(&pmlmepriv->lock); +} + +static inline void clr_fwstate_ex(struct mlme_priv *pmlmepriv, int state) +{ + spin_lock_bh(&pmlmepriv->lock); + _clr_fwstate_(pmlmepriv, state); + spin_unlock_bh(&pmlmepriv->lock); +} + +u16 rtw_get_capability23a(struct wlan_bssid_ex *bss); +void rtw_update_scanned_network23a(struct rtw_adapter *adapter, + struct wlan_bssid_ex *target); +void rtw_disconnect_hdl23a_under_linked(struct rtw_adapter *adapter, + struct sta_info *psta, u8 free_assoc); +void rtw_generate_random_ibss23a(u8 *pibss); +struct wlan_network *rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr); +struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue); + +void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, + int lock_scanned_queue); +void rtw_indicate_disconnect23a(struct rtw_adapter *adapter); +void rtw_indicate_connect23a(struct rtw_adapter *adapter); +void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted); +void rtw_scan_abort23a(struct rtw_adapter *adapter); + +int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, + uint in_len); +int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie, + uint in_len, uint initial_out_len); +void rtw_init_registrypriv_dev_network23a(struct rtw_adapter *adapter); + +void rtw_update_registrypriv_dev_network23a(struct rtw_adapter *adapter); + +void rtw_get_encrypt_decrypt_from_registrypriv23a(struct rtw_adapter *adapter); + +void rtw_scan_timeout_handler23a(unsigned long data); + +void rtw_dynamic_check_timer_handler(unsigned long data); +bool rtw_is_scan_deny(struct rtw_adapter *adapter); +void rtw_clear_scan_deny(struct rtw_adapter *adapter); +void rtw_set_scan_deny_timer_hdl(unsigned long data); +void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms); + +int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter); + +void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv); + +void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv); + +struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv); + +void _rtw_free_network23a(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork, u8 isfreeall); +void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv, + struct wlan_network *pnetwork); + +struct wlan_network *_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr); + +void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall); + +int rtw_if_up23a(struct rtw_adapter *padapter); + +int rtw_linked_check(struct rtw_adapter *padapter); + +u8 *rtw_get_capability23a_from_ie(u8 *ie); +u8 *rtw_get_timestampe_from_ie23a(u8 *ie); +u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie); + + +void rtw_joinbss_reset23a(struct rtw_adapter *padapter); + +unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie, + u8 *out_ie, uint in_len, uint *pout_len); +void rtw_update_ht_cap23a(struct rtw_adapter *padapter, + u8 *pie, uint ie_len); +void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); + +int rtw_is_same_ibss23a(struct rtw_adapter *adapter, + struct wlan_network *pnetwork); +int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst); + +void _rtw23a_roaming(struct rtw_adapter *adapter, + struct wlan_network *tgt_network); +void rtw23a_roaming(struct rtw_adapter *adapter, + struct wlan_network *tgt_network); +void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming); +u8 rtw_to_roaming(struct rtw_adapter *adapter); +void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta); + +#endif /* __RTL871X_MLME_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h new file mode 100644 index 000000000000..d1c2d71295e5 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h @@ -0,0 +1,782 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_MLME_EXT_H_ +#define __RTW_MLME_EXT_H_ + +#include +#include +#include + + +/* Commented by Albert 20101105 */ +/* Increase the SURVEY_TO value from 100 to 150 ( 100ms to 150ms ) */ +/* The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. */ +/* So, this driver tried to extend the dwell time for each scanning channel. */ +/* This will increase the chance to receive the probe response from SoftAP. */ + +#define SURVEY_TO (100) +#define REAUTH_TO (300) /* 50) */ +#define REASSOC_TO (300) /* 50) */ +/* define DISCONNECT_TO (3000) */ +#define ADDBA_TO (2000) + +#define LINKED_TO (1) /* unit:2 sec, 1x2=2 sec */ + +#define REAUTH_LIMIT (4) +#define REASSOC_LIMIT (4) +#define READDBA_LIMIT (2) + +#define ROAMING_LIMIT 8 + +#define DYNAMIC_FUNC_DISABLE (0x0) + +/* ====== enum odm_ability ======== */ +/* BB ODM section BIT 0-15 */ +#define DYNAMIC_BB_DIG BIT(0) +#define DYNAMIC_BB_RA_MASK BIT(1) +#define DYNAMIC_BB_DYNAMIC_TXPWR BIT(2) +#define DYNAMIC_BB_BB_FA_CNT BIT(3) + +#define DYNAMIC_BB_RSSI_MONITOR BIT(4) +#define DYNAMIC_BB_CCK_PD BIT(5) +#define DYNAMIC_BB_ANT_DIV BIT(6) +#define DYNAMIC_BB_PWR_SAVE BIT(7) +#define DYNAMIC_BB_PWR_TRAIN BIT(8) +#define DYNAMIC_BB_RATE_ADAPTIVE BIT(9) +#define DYNAMIC_BB_PATH_DIV BIT(10) +#define DYNAMIC_BB_PSD BIT(11) + +/* MAC DM section BIT 16-23 */ +#define DYNAMIC_MAC_struct edca_turboURBO BIT(16) +#define DYNAMIC_MAC_EARLY_MODE BIT(17) + +/* RF ODM section BIT 24-31 */ +#define DYNAMIC_RF_TX_PWR_TRACK BIT(24) +#define DYNAMIC_RF_RX_GAIN_TRACK BIT(25) +#define DYNAMIC_RF_CALIBRATION BIT(26) + +#define DYNAMIC_ALL_FUNC_ENABLE 0xFFFFFFF + +#define _HW_STATE_NOLINK_ 0x00 +#define _HW_STATE_ADHOC_ 0x01 +#define _HW_STATE_STATION_ 0x02 +#define _HW_STATE_AP_ 0x03 + + +#define _1M_RATE_ 0 +#define _2M_RATE_ 1 +#define _5M_RATE_ 2 +#define _11M_RATE_ 3 +#define _6M_RATE_ 4 +#define _9M_RATE_ 5 +#define _12M_RATE_ 6 +#define _18M_RATE_ 7 +#define _24M_RATE_ 8 +#define _36M_RATE_ 9 +#define _48M_RATE_ 10 +#define _54M_RATE_ 11 + + +extern unsigned char RTW_WPA_OUI23A[]; +extern unsigned char WMM_OUI23A[]; +extern unsigned char WPS_OUI23A[]; +extern unsigned char WFD_OUI23A[]; +extern unsigned char P2P_OUI23A[]; + +extern unsigned char WMM_INFO_OUI23A[]; +extern unsigned char WMM_PARA_OUI23A[]; + + +/* */ +/* Channel Plan Type. */ +/* Note: */ +/* We just add new channel plan when the new channel plan is different from any of the following */ +/* channel plan. */ +/* If you just wnat to customize the acitions(scan period or join actions) about one of the channel plan, */ +/* customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */ +/* */ +enum { /* _RT_CHANNEL_DOMAIN */ + /* old channel plan mapping ===== */ + RT_CHANNEL_DOMAIN_FCC = 0x00, + RT_CHANNEL_DOMAIN_IC = 0x01, + RT_CHANNEL_DOMAIN_ETSI = 0x02, + RT_CHANNEL_DOMAIN_SPAIN = 0x03, + RT_CHANNEL_DOMAIN_FRANCE = 0x04, + RT_CHANNEL_DOMAIN_MKK = 0x05, + RT_CHANNEL_DOMAIN_MKK1 = 0x06, + RT_CHANNEL_DOMAIN_ISRAEL = 0x07, + RT_CHANNEL_DOMAIN_TELEC = 0x08, + RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09, + RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A, + RT_CHANNEL_DOMAIN_TAIWAN = 0x0B, + RT_CHANNEL_DOMAIN_CHINA = 0x0C, + RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D, + RT_CHANNEL_DOMAIN_KOREA = 0x0E, + RT_CHANNEL_DOMAIN_TURKEY = 0x0F, + RT_CHANNEL_DOMAIN_JAPAN = 0x10, + RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11, + RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12, + RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13, + RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14, + + /* new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */ + RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20, + RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21, + RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22, + RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23, + RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24, + RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25, + RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26, + RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27, + RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28, + RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29, + RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30, + RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31, + RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32, + RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33, + RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34, + RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35, + RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36, + RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37, + RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38, + RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39, + RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40, + RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41, + /* Add new channel plan above this line=============== */ + RT_CHANNEL_DOMAIN_MAX, + RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F, +}; + +enum { /* _RT_CHANNEL_DOMAIN_2G */ + RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, /* Worldwird 13 */ + RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, /* Europe */ + RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, /* US */ + RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03, /* Japan */ + RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04, /* France */ + RT_CHANNEL_DOMAIN_2G_NULL = 0x05, + /* Add new channel plan above this line=============== */ + RT_CHANNEL_DOMAIN_2G_MAX, +}; + +enum { /* _RT_CHANNEL_DOMAIN_5G */ + RT_CHANNEL_DOMAIN_5G_NULL = 0x00, + RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01, /* Europe */ + RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02, /* Australia, New Zealand */ + RT_CHANNEL_DOMAIN_5G_ETSI3 = 0x03, /* Russia */ + RT_CHANNEL_DOMAIN_5G_FCC1 = 0x04, /* US */ + RT_CHANNEL_DOMAIN_5G_FCC2 = 0x05, /* FCC o/w DFS Channels */ + RT_CHANNEL_DOMAIN_5G_FCC3 = 0x06, /* India, Mexico */ + RT_CHANNEL_DOMAIN_5G_FCC4 = 0x07, /* Venezuela */ + RT_CHANNEL_DOMAIN_5G_FCC5 = 0x08, /* China */ + RT_CHANNEL_DOMAIN_5G_FCC6 = 0x09, /* Israel */ + RT_CHANNEL_DOMAIN_5G_FCC7_IC1 = 0x0A, /* US, Canada */ + RT_CHANNEL_DOMAIN_5G_KCC1 = 0x0B, /* Korea */ + RT_CHANNEL_DOMAIN_5G_MKK1 = 0x0C, /* Japan */ + RT_CHANNEL_DOMAIN_5G_MKK2 = 0x0D, /* Japan (W52, W53) */ + RT_CHANNEL_DOMAIN_5G_MKK3 = 0x0E, /* Japan (W56) */ + RT_CHANNEL_DOMAIN_5G_NCC1 = 0x0F, /* Taiwan */ + RT_CHANNEL_DOMAIN_5G_NCC2 = 0x10, /* Taiwan o/w DFS */ + /* Add new channel plan above this line=============== */ + /* Driver Self Defined ===== */ + RT_CHANNEL_DOMAIN_5G_FCC = 0x11, + RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x12, + RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x13, + RT_CHANNEL_DOMAIN_5G_MAX, +}; + +#define rtw_is_channel_plan_valid(chplan) (chplansurvey_timer, jiffies + msecs_to_jiffies(ms)); + +#define set_link_timer(mlmeext, ms) \ + /*DBG_8723A("%s set_link_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \ + mod_timer(&mlmeext->link_timer, jiffies + msecs_to_jiffies(ms)); + +int cckrates_included23a(unsigned char *rate, int ratelen); +int cckratesonly_included23a(unsigned char *rate, int ratelen); + +void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr); + +void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); +void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext); + +struct cmd_hdl { + uint parmsize; + u8 (*h2cfuns)(struct rtw_adapter *padapter, u8 *pbuf); +}; + + +u8 read_macreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 write_macreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 read_bbreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 write_bbreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 read_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 write_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf); + + +u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 disconnect_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 setauth_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 set_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 del_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf); +u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); + +u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf); +u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); +u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); /* Kurt: Handling DFS channel switch announcement ie. */ +u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf); + +#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl23a}, +#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, + +struct C2HEvent_Header { +#ifdef __LITTLE_ENDIAN + + unsigned int len:16; + unsigned int ID:8; + unsigned int seq:8; + +#elif defined(__BIG_ENDIAN) + + unsigned int seq:8; + unsigned int ID:8; + unsigned int len:16; + +#else + +# error "Must be LITTLE or BIG Endian" + +#endif + + unsigned int rsvd; +}; + +void rtw_dummy_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf); +void rtw23a_fwdbg_event_callback(struct rtw_adapter *adapter , u8 *pbuf); + +enum rtw_c2h_event { + GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ + GEN_EVT_CODE(_Read_BBREG), + GEN_EVT_CODE(_Read_RFREG), + GEN_EVT_CODE(_Read_EEPROM), + GEN_EVT_CODE(_Read_EFUSE), + GEN_EVT_CODE(_Read_CAM), /*5*/ + GEN_EVT_CODE(_Get_BasicRate), + GEN_EVT_CODE(_Get_DataRate), + GEN_EVT_CODE(_Survey), /*8*/ + GEN_EVT_CODE(_SurveyDone), /*9*/ + + GEN_EVT_CODE(_JoinBss) , /*10*/ + GEN_EVT_CODE(_AddSTA), + GEN_EVT_CODE(_DelSTA), + GEN_EVT_CODE(_AtimDone) , + GEN_EVT_CODE(_TX_Report), + GEN_EVT_CODE(_CCX_Report), /*15*/ + GEN_EVT_CODE(_DTM_Report), + GEN_EVT_CODE(_TX_Rate_Statistics), + GEN_EVT_CODE(_C2HLBK), + GEN_EVT_CODE(_FWDBG), + GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ + GEN_EVT_CODE(_ADDBA), + GEN_EVT_CODE(_C2HBCN), + GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */ + GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE, work around ASPM */ + MAX_C2HEVT +}; + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_p2p.h b/drivers/staging/rtl8723au/include/rtw_p2p.h new file mode 100644 index 000000000000..93fdc658ff4d --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_p2p.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_P2P_H_ +#define __RTW_P2P_H_ + +#include + +u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, + u8 *pssid, u8 ussidlen, u8 *pdev_raddr); +u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, + u8 status_code); +u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf); +#ifdef CONFIG_8723AU_P2P +u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, + u8 tunneled); +u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); +#endif /* CONFIG_8723AU_P2P */ + +u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len); +u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len, struct sta_info *psta); +u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len); +u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len); +u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, + uint len); +u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe); +u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, + u8 *pframe, uint len); +u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, + u8 *pframe, uint len); +u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo, + u8 *pframe, uint len); +u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo, + u8 *pframe, uint len); + +void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int cmdtype); + +#ifdef CONFIG_8723AU_P2P +void process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength); +void p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state); +u8 p2p_ps_wk_cmd23a(struct rtw_adapter *padapter, u8 p2p_ps_state, u8 enqueue); +#endif /* CONFIG_8723AU_P2P */ + +void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter); +int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf, + u32 len, u8 tx); +void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32 *len); + +void reset_global_wifidirect_info23a(struct rtw_adapter *padapter); +int rtw_init_wifi_display_info(struct rtw_adapter *padapter); +void rtw_init_wifidirect_timers23a(struct rtw_adapter *padapter); +void rtw_init_wifidirect_addrs23a(struct rtw_adapter *padapter, u8 *dev_addr, + u8 *iface_addr); +void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role); +int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role); + +static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo, + enum P2P_STATE state) +{ + if (wdinfo->p2p_state != state) { + /* wdinfo->pre_p2p_state = wdinfo->p2p_state; */ + wdinfo->p2p_state = state; + } +} + +static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, + enum P2P_STATE state) +{ + if (wdinfo->pre_p2p_state != state) + wdinfo->pre_p2p_state = state; +} + +static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, + enum P2P_ROLE role) +{ + if (wdinfo->role != role) + wdinfo->role = role; +} + +static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo) +{ + return wdinfo->p2p_state; +} + +static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo) +{ + return wdinfo->pre_p2p_state; +} + +static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo) +{ + return wdinfo->role; +} + +static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo, + enum P2P_STATE state) +{ + return wdinfo->p2p_state == state; +} + +static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo, + enum P2P_ROLE role) +{ + return wdinfo->role == role; +} + +#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state) +#define rtw_p2p_set_pre_state(wdinfo, state) \ + _rtw_p2p_set_pre_state(wdinfo, state) +#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role) + +#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo) +#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo) +#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo) +#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state) +#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role) + +#define rtw_p2p_findphase_ex_set(wdinfo, value) \ + ((wdinfo)->find_phase_state_exchange_cnt = (value)) + +/* is this find phase exchange for social channel scan? */ +#define rtw_p2p_findphase_ex_is_social(wdinfo) \ + ((wdinfo)->find_phase_state_exchange_cnt >= \ + P2P_FINDPHASE_EX_SOCIAL_FIRST) + +/* should we need find phase exchange anymore? */ +#define rtw_p2p_findphase_ex_is_needed(wdinfo) \ + ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \ + (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE) + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h new file mode 100644 index 000000000000..b42e14198e8d --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h @@ -0,0 +1,265 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_PWRCTRL_H_ +#define __RTW_PWRCTRL_H_ + +#include +#include + +#define FW_PWR0 0 +#define FW_PWR1 1 +#define FW_PWR2 2 +#define FW_PWR3 3 + + +#define HW_PWR0 7 +#define HW_PWR1 6 +#define HW_PWR2 2 +#define HW_PWR3 0 +#define HW_PWR4 8 + +#define FW_PWRMSK 0x7 + + +#define XMIT_ALIVE BIT(0) +#define RECV_ALIVE BIT(1) +#define CMD_ALIVE BIT(2) +#define EVT_ALIVE BIT(3) + +enum Power_Mgnt { + PS_MODE_ACTIVE = 0, + PS_MODE_MIN, + PS_MODE_MAX, + PS_MODE_DTIM, + PS_MODE_VOIP, + PS_MODE_UAPSD_WMM, + PS_MODE_UAPSD, + PS_MODE_IBSS, + PS_MODE_WWLAN, + PM_Radio_Off, + PM_Card_Disable, + PS_MODE_NUM +}; + + +/* BIT[2:0] = HW state + * BIT[3] = Protocol PS state, 0: active, 1: sleep state + * BIT[4] = sub-state + */ + +#define PS_DPS BIT(0) +#define PS_LCLK (PS_DPS) +#define PS_RF_OFF BIT(1) +#define PS_ALL_ON BIT(2) +#define PS_ST_ACTIVE BIT(3) + +#define PS_ISR_ENABLE BIT(4) +#define PS_IMR_ENABLE BIT(5) +#define PS_ACK BIT(6) +#define PS_TOGGLE BIT(7) + +#define PS_STATE_MASK (0x0F) +#define PS_STATE_HW_MASK (0x07) +#define PS_SEQ_MASK (0xc0) + +#define PS_STATE(x) (PS_STATE_MASK & (x)) +#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) +#define PS_SEQ(x) (PS_SEQ_MASK & (x)) + +#define PS_STATE_S0 (PS_DPS) +#define PS_STATE_S1 (PS_LCLK) +#define PS_STATE_S2 (PS_RF_OFF) +#define PS_STATE_S3 (PS_ALL_ON) +#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) + + +#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) +#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) +#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) + + +struct reportpwrstate_parm { + unsigned char mode; + unsigned char state; /* the CPWM value */ + unsigned short rsvd; +}; + +#define LPS_DELAY_TIME (1*HZ) /* 1 sec */ + +#define EXE_PWR_NONE 0x01 +#define EXE_PWR_IPS 0x02 +#define EXE_PWR_LPS 0x04 + +/* RF state. */ +enum rt_rf_power_state { + rf_on, /* RF is on after RFSleep or RFOff */ + rf_sleep, /* 802.11 Power Save mode */ + rf_off, /* HW/SW Radio OFF or Inactive Power Save */ + /* Add the new RF state above this line===== */ + rf_max +}; + +/* RF Off Level for IPS or HW/SW radio off */ +#define RT_RF_OFF_LEVL_ASPM BIT(0) /* PCI ASPM */ +#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /* PCI clock request */ +#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /* PCI D3 mode */ +/* NIC halt, re-init hw params */ +#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) +/* FW free, re-download the FW */ +#define RT_RF_OFF_LEVL_FREE_FW BIT(4) +#define RT_RF_OFF_LEVL_FW_32K BIT(5) /* FW in 32k */ +/* Always enable ASPM and Clock Req in initialization. */ +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) +/* When LPS is on, disable 2R if no packet is received or transmittd. */ +#define RT_RF_LPS_DISALBE_2R BIT(30) +#define RT_RF_LPS_LEVEL_ASPM BIT(31) /* LPS with ASPM */ + +#define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) \ + ((ppsc->cur_ps_level & _PS_FLAG) ? true : false) +#define RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG) \ + (ppsc->cur_ps_level &= (~(_PS_FLAG))) +#define RT_SET_PS_LEVEL(ppsc, _PS_FLAG) \ + (ppsc->cur_ps_level |= _PS_FLAG) + + +enum { + PSBBREG_RF0 = 0, + PSBBREG_RF1, + PSBBREG_RF2, + PSBBREG_AFE0, + PSBBREG_TOTALCNT +}; + +enum { /* for ips_mode */ + IPS_NONE = 0, + IPS_NORMAL, + IPS_LEVEL_2, +}; + +struct pwrctrl_priv { + struct semaphore lock; + volatile u8 rpwm; /* requested power state for fw */ + volatile u8 cpwm; /* fw current power state. updated when 1. + * read from HCPWM 2. driver lowers power level + */ + volatile u8 tog; /* toggling */ + volatile u8 cpwm_tog; /* toggling */ + + u8 pwr_mode; + u8 smart_ps; + u8 bcn_ant_mode; + + u32 alives; + struct work_struct cpwm_event; + u8 bpower_saving; + + u8 b_hw_radio_off; + u8 reg_rfoff; + u8 reg_pdnmode; /* powerdown mode */ + u32 rfoff_reason; + + /* RF OFF Level */ + u32 cur_ps_level; + u32 reg_rfps_level; + + uint ips_enter23a_cnts; + uint ips_leave23a_cnts; + + u8 ips_mode; + u8 ips_mode_req; /* used to accept the mode setting request */ + uint bips_processing; + u32 ips_deny_time; /* will deny IPS when system time is smaller */ + u8 ps_processing; /* used to mark whether in rtw_ps_processor23a */ + + u8 bLeisurePs; + u8 LpsIdleCount; + u8 power_mgnt; + u8 bFwCurrentInPSMode; + unsigned long DelayLPSLastTimeStamp; + u8 btcoex_rfon; + s32 pnp_current_pwr_state; + u8 pnp_bstop_trx; + + u8 bInternalAutoSuspend; + u8 bInSuspend; +#ifdef CONFIG_8723AU_BT_COEXIST + u8 bAutoResume; + u8 autopm_cnt; +#endif + u8 bSupportRemoteWakeup; + struct timer_list pwr_state_check_timer; + int pwr_state_check_interval; + u8 pwr_state_check_cnts; + + int ps_flag; + + enum rt_rf_power_state rf_pwrstate;/* cur power state */ + enum rt_rf_power_state change_rfpwrstate; + + u8 wepkeymask; + u8 bHWPowerdown;/* if support hw power down */ + u8 bHWPwrPindetect; + u8 bkeepfwalive; + u8 brfoffbyhw; + unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT]; +}; + +#define rtw_get_ips_mode_req(pwrctrlpriv) \ + ((pwrctrlpriv)->ips_mode_req) + +#define rtw_ips_mode_req(pwrctrlpriv, ips_mode) \ + ((pwrctrlpriv)->ips_mode_req = (ips_mode)) + +#define RTW_PWR_STATE_CHK_INTERVAL 2000 + +#define _rtw_set_pwr_state_check_timer(pwrctrlpriv, ms) \ + (mod_timer(&pwrctrlpriv->pwr_state_check_timer, jiffies + \ + msecs_to_jiffies(ms))) + +#define rtw_set_pwr_state_check_timer(pwrctrlpriv) \ + (_rtw_set_pwr_state_check_timer((pwrctrlpriv), \ + (pwrctrlpriv)->pwr_state_check_interval)) + +void rtw_init_pwrctrl_priv23a(struct rtw_adapter *adapter); +void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter); + +void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, + u8 smart_ps, u8 bcn_ant_mode); +void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 val8); +void LeaveAllPowerSaveMode23a(struct rtw_adapter *adapter); +void ips_enter23a(struct rtw_adapter *padapter); +int ips_leave23a(struct rtw_adapter *padapter); + +void rtw_ps_processor23a(struct rtw_adapter *padapter); + +enum rt_rf_power_state RfOnOffDetect23a(struct rtw_adapter *adapter); + +s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms); +void LPS_Enter23a(struct rtw_adapter *padapter); +void LPS_Leave23a(struct rtw_adapter *padapter); + +u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, + enum hal_intf_ps_func efunc_id, u8 *val); +void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms); +int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, + const char *caller); +#define rtw_pwr_wakeup(adapter) _rtw_pwr_wakeup23a(adapter, \ + RTW_PWR_STATE_CHK_INTERVAL, __func__) +#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms) \ + _rtw_pwr_wakeup23a(adapter, ips_deffer_ms, __func__) +int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode); +int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode); + +#endif /* __RTL871X_PWRCTRL_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_qos.h b/drivers/staging/rtl8723au/include/rtw_qos.h new file mode 100644 index 000000000000..68fc5ba1844a --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_qos.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +#ifndef _RTW_QOS_H_ +#define _RTW_QOS_H_ + +#include + +struct qos_priv { + /* bit mask option: u-apsd, s-apsd, ts, block ack... */ + unsigned int qos_option; +}; + +#endif /* _RTL871X_QOS_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_recv.h b/drivers/staging/rtl8723au/include/rtw_recv.h new file mode 100644 index 000000000000..e2462e052e44 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_recv.h @@ -0,0 +1,319 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_RECV_H_ +#define _RTW_RECV_H_ + +#include +#include + +#define NR_RECVFRAME 256 + +#define MAX_RXFRAME_CNT 512 +#define MAX_RX_NUMBLKS (32) +#define RECVFRAME_HDR_ALIGN 128 + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define MAX_SUBFRAME_COUNT 64 + +/* for Rx reordering buffer control */ +struct recv_reorder_ctrl { + struct rtw_adapter *padapter; + u8 enable; + u16 indicate_seq;/* wstart_b, init_value=0xffff */ + u16 wend_b; + u8 wsize_b; + struct rtw_queue pending_recvframe_queue; + struct timer_list reordering_ctrl_timer; +}; + +struct stainfo_rxcache { + u16 tid_rxseq[16]; +/* + unsigned short tid0_rxseq; + unsigned short tid1_rxseq; + unsigned short tid2_rxseq; + unsigned short tid3_rxseq; + unsigned short tid4_rxseq; + unsigned short tid5_rxseq; + unsigned short tid6_rxseq; + unsigned short tid7_rxseq; + unsigned short tid8_rxseq; + unsigned short tid9_rxseq; + unsigned short tid10_rxseq; + unsigned short tid11_rxseq; + unsigned short tid12_rxseq; + unsigned short tid13_rxseq; + unsigned short tid14_rxseq; + unsigned short tid15_rxseq; +*/ +}; + +struct smooth_rssi_data { + u32 elements[100]; /* array to store values */ + u32 index; /* index to current array to store */ + u32 total_num; /* num of valid elements */ + u32 total_val; /* sum of valid elements */ +}; + +struct signal_stat { + u8 update_req; /* used to indicate */ + u8 avg_val; /* avg of valid elements */ + u32 total_num; /* num of valid elements */ + u32 total_val; /* sum of valid elements */ +}; + +#define MAX_PATH_NUM_92CS 2 + +struct phy_info { + u8 RxPWDBAll; + u8 SignalQuality; /* in 0-100 index. */ + u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */ + u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* 0~100 */ + s8 RxPower; /* in dBm Translate from PWdB */ + /* Real power in dBm for this packet, no beautification and aggregation. + * Keep this raw info to be used for the other procedures. + */ + s8 RecvSignalPower; + u8 BTRxRSSIPercentage; + u8 SignalStrength; /* in 0-100 index. */ + u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */ + u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */ +}; + + +struct rx_pkt_attrib { + u16 pkt_len; + u8 physt; + u8 drvinfo_sz; + u8 shift_sz; + u8 hdrlen; /* the WLAN Header Len */ + u8 to_fr_ds; + u8 amsdu; + u8 qos; + u8 priority; + u8 pw_save; + u8 mdata; + u16 seq_num; + u8 frag_num; + u8 mfrag; + u8 order; + u8 privacy; /* in frame_ctrl field */ + u8 bdecrypted; + /* when 0 indicate no encrypt. when non-zero, indicate the algorith */ + u8 encrypt; + u8 iv_len; + u8 icv_len; + u8 crc_err; + u8 icv_err; + + u16 eth_type; + + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 ta[ETH_ALEN]; + u8 ra[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + + u8 ack_policy; + + u8 tcpchk_valid; /* 0: invalid, 1: valid */ + u8 ip_chkrpt; /* 0: incorrect, 1: correct */ + u8 tcp_chkrpt; /* 0: incorrect, 1: correct */ + u8 key_index; + + u8 mcs_rate; + u8 rxht; + u8 sgi; + u8 pkt_rpt_type; + u32 MacIDValidEntry[2]; /* 64 bits present 64 entry. */ + struct phy_info phy_info; +}; + +/* These definition is used for Rx packet reordering. */ +#define SN_LESS(a, b) (((a-b) & 0x800) != 0) +#define SN_EQUAL(a, b) (a == b) +#define REORDER_WAIT_TIME (50) /* (ms) */ + +#define RECVBUFF_ALIGN_SZ 8 + +#define RXDESC_SIZE 24 +#define RXDESC_OFFSET RXDESC_SIZE + +struct recv_stat { + unsigned int rxdw0; + unsigned int rxdw1; + unsigned int rxdw2; + unsigned int rxdw3; + unsigned int rxdw4; + unsigned int rxdw5; +}; + +/* accesser of recv_priv: rtw_recv_entry23a(dispatch / passive level); \ + * recv_thread(passive) ; returnpkt(dispatch) ; halt(passive) ; + * + * using enter_critical section to protect + */ +struct recv_priv { + spinlock_t lock; + + struct rtw_queue free_recv_queue; + struct rtw_queue recv_pending_queue; + struct rtw_queue uc_swdec_pending_queue; + + void *pallocated_frame_buf; + + uint free_recvframe_cnt; + + struct rtw_adapter *adapter; + + u32 bIsAnyNonBEPkts; + u64 rx_bytes; + u64 rx_pkts; + u64 rx_drop; + u64 last_rx_bytes; + + uint rx_icv_err; + uint rx_largepacket_crcerr; + uint rx_smallpacket_crcerr; + uint rx_middlepacket_crcerr; + + /* u8 *pallocated_urb_buf; */ + struct semaphore allrxreturnevt; + uint ff_hwaddr; + u8 rx_pending_cnt; + + struct urb *int_in_urb; + + u8 *int_in_buf; + + struct tasklet_struct irq_prepare_beacon_tasklet; + struct tasklet_struct recv_tasklet; + struct sk_buff_head free_recv_skb_queue; + struct sk_buff_head rx_skb_queue; + u8 *precv_buf; + struct rtw_queue free_recv_buf_queue; + u32 free_recv_buf_queue_cnt; + + /* For display the phy informatiom */ + u8 is_signal_dbg; /* for debug */ + u8 signal_strength_dbg; /* for debug */ + s8 rssi; + s8 rxpwdb; + u8 signal_strength; + u8 signal_qual; + u8 noise; + int RxSNRdB[2]; + s8 RxRssi[2]; + int FalseAlmCnt_all; + + struct timer_list signal_stat_timer; + u32 signal_stat_sampling_interval; + /* u32 signal_stat_converging_constant; */ + struct signal_stat signal_qual_data; + struct signal_stat signal_strength_data; +}; + +#define rtw_set_signal_stat_timer(recvpriv) \ + mod_timer(&(recvpriv)->signal_stat_timer, jiffies + \ + msecs_to_jiffies((recvpriv)->signal_stat_sampling_interval)) + +struct sta_recv_priv { + spinlock_t lock; + int option; + + /* struct rtw_queue blk_strms[MAX_RX_NUMBLKS]; */ + struct rtw_queue defrag_q; /* keeping the fragment frame until defrag */ + + struct stainfo_rxcache rxcache; + + /* uint sta_rx_bytes; */ + /* uint sta_rx_pkts; */ + /* uint sta_rx_fail; */ + +}; + + +struct recv_buf { + struct list_head list; + + struct rtw_adapter *adapter; + + struct urb *purb; + struct sk_buff *pskb; +}; + +/* head -----> + * + * data -----> + * + * payload + * + * tail -----> + * + * end -----> + * + * len = (unsigned int )(tail - data); + * + */ +struct recv_frame { + struct list_head list; + struct sk_buff *pkt; + + struct rtw_adapter *adapter; + + struct rx_pkt_attrib attrib; + + struct sta_info *psta; + + /* for A-MPDU Rx reordering buffer control */ + struct recv_reorder_ctrl *preorder_ctrl; +}; + +/* get a free recv_frame from pfree_recv_queue */ +struct recv_frame *rtw_alloc_recvframe23a(struct rtw_queue *pfree_recv_queue); +int rtw_free_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *pfree_recv_queue); + +int rtw_enqueue_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *queue); + +void rtw_free_recvframe23a_queue(struct rtw_queue *pframequeue, struct rtw_queue *pfree_recv_queue); +u32 rtw_free_uc_swdec_pending_queue23a(struct rtw_adapter *adapter); + +int rtw_enqueue_recvbuf23a_to_head(struct recv_buf *precvbuf, struct rtw_queue *queue); +int rtw_enqueue_recvbuf23a(struct recv_buf *precvbuf, struct rtw_queue *queue); +struct recv_buf *rtw_dequeue_recvbuf23a(struct rtw_queue *queue); + +void rtw_reordering_ctrl_timeout_handler23a(unsigned long pcontext); + +static inline s32 translate_percentage_to_dbm(u32 SignalStrengthIndex) +{ + s32 SignalPower; /* in dBm. */ + + /* Translate to dBm (x=0.5y-95). */ + SignalPower = (s32)((SignalStrengthIndex + 1) >> 1); + SignalPower -= 95; + + return SignalPower; +} + + +struct sta_info; + +void _rtw_init_sta_recv_priv23a(struct sta_recv_priv *psta_recvpriv); + +void mgt_dispatcher23a(struct rtw_adapter *padapter, + struct recv_frame *precv_frame); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_rf.h b/drivers/staging/rtl8723au/include/rtw_rf.h new file mode 100644 index 000000000000..91a0a22a2709 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_rf.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_RF_H_ +#define __RTW_RF_H_ + +#include + +#define OFDM_PHY 1 +#define MIXED_PHY 2 +#define CCK_PHY 3 + +#define NumRates (13) + +/* slot time for 11g */ +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + +/* We now define the max channels in each channel plan. */ +#define MAX_CHANNEL_NUM_2G 14 +#define MAX_CHANNEL_NUM_5G 24 +#define MAX_CHANNEL_NUM 38/* 14+24 */ + +/* define NUM_REGULATORYS 21 */ +#define NUM_REGULATORYS 1 + +/* Country codes */ +#define USA 0x555320 +#define EUROPE 0x1 /* temp, should be provided later */ +#define JAPAN 0x2 /* temp, should be provided later */ + +struct regulatory_class { + u32 starting_freq; /* MHz, */ + u8 channel_set[MAX_CHANNEL_NUM]; + u8 channel_cck_power[MAX_CHANNEL_NUM];/* dbm */ + u8 channel_ofdm_power[MAX_CHANNEL_NUM];/* dbm */ + u8 txpower_limit; /* dbm */ + u8 channel_spacing; /* MHz */ + u8 modem; +}; + +enum { + cESS = 0x0001, + cIBSS = 0x0002, + cPollable = 0x0004, + cPollReq = 0x0008, + cPrivacy = 0x0010, + cShortPreamble = 0x0020, + cPBCC = 0x0040, + cChannelAgility = 0x0080, + cSpectrumMgnt = 0x0100, + cQos = 0x0200, /* For HCCA, use with CF-Pollable and CF-PollReq */ + cShortSlotTime = 0x0400, + cAPSD = 0x0800, + cRM = 0x1000, /* RRM (Radio Request Measurement) */ + cDSSS_OFDM = 0x2000, + cDelayedBA = 0x4000, + cImmediateBA = 0x8000, +}; + +enum { + PREAMBLE_LONG = 1, + PREAMBLE_AUTO = 2, + PREAMBLE_SHORT = 3, +}; + +/* Bandwidth Offset */ +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +/* Represent Channel Width in HT Capabilities */ +enum ht_channel_width { + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_40 = 1, + HT_CHANNEL_WIDTH_80 = 2, + HT_CHANNEL_WIDTH_160 = 3, + HT_CHANNEL_WIDTH_10 = 4, +}; + +/* */ +/* Represent Extention Channel Offset in HT Capabilities */ +/* This is available only in 40Mhz mode. */ +/* */ +enum { + HT_EXTCHNL_OFFSET_NO_EXT = 0, + HT_EXTCHNL_OFFSET_UPPER = 1, + HT_EXTCHNL_OFFSET_NO_DEF = 2, + HT_EXTCHNL_OFFSET_LOWER = 3, +}; + +/* 2007/11/15 MH Define different RF type. */ +enum { + RF_1T2R = 0, + RF_2T4R = 1, + RF_2T2R = 2, + RF_1T1R = 3, + RF_2T2R_GREEN = 4, + RF_819X_MAX_TYPE = 5, +}; + +#endif /* _RTL8711_RF_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_security.h b/drivers/staging/rtl8723au/include/rtw_security.h new file mode 100644 index 000000000000..75bbb934a53c --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_security.h @@ -0,0 +1,357 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __RTW_SECURITY_H_ +#define __RTW_SECURITY_H_ + +#include +#include + + +#define _NO_PRIVACY_ 0x0 +#define _WEP40_ 0x1 +#define _TKIP_ 0x2 +#define _TKIP_WTMIC_ 0x3 +#define _AES_ 0x4 +#define _WEP104_ 0x5 +#define _WEP_WPA_MIXED_ 0x07 /* WEP + WPA */ +#define _SMS4_ 0x06 + +#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_)) + +#define _WPA_IE_ID_ 0xdd +#define _WPA2_IE_ID_ 0x30 + +#define SHA256_MAC_LEN 32 +#define AES_BLOCK_SIZE 16 +#define AES_PRIV_SIZE (4 * 44) + +enum ENCRYP_PROTOCOL { + ENCRYP_PROTOCOL_OPENSYS, /* open system */ + ENCRYP_PROTOCOL_WEP, /* WEP */ + ENCRYP_PROTOCOL_WPA, /* WPA */ + ENCRYP_PROTOCOL_WPA2, /* WPA2 */ + ENCRYP_PROTOCOL_MAX +}; + +#ifndef Ndis802_11AuthModeWPA2 +#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) +#endif + +#ifndef Ndis802_11AuthModeWPA2PSK +#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) +#endif + +union pn48 { + u64 val; + +#ifdef __LITTLE_ENDIAN + +struct { + u8 TSC0; + u8 TSC1; + u8 TSC2; + u8 TSC3; + u8 TSC4; + u8 TSC5; + u8 TSC6; + u8 TSC7; +} _byte_; + +#elif defined(__BIG_ENDIAN) + +struct { + u8 TSC7; + u8 TSC6; + u8 TSC5; + u8 TSC4; + u8 TSC3; + u8 TSC2; + u8 TSC1; + u8 TSC0; +} _byte_; +#else +#error Need BIG or LITTLE endian + +#endif + +}; + +union Keytype { + u8 skey[16]; + u32 lkey[4]; +}; + + +struct rt_pmkid_list { + u8 bUsed; + u8 Bssid[6]; + u8 PMKID[16]; + u8 SsidBuf[33]; + u8 *ssid_octet; + u16 ssid_length; +}; + +struct security_priv { + u32 dot11AuthAlgrthm; /* 802.11 auth, could be open, shared, + * 8021x and authswitch */ + u32 dot11PrivacyAlgrthm; /* This specifies the privacy for + * shared auth. algorithm. + */ + /* WEP */ + u32 dot11PrivacyKeyIndex; /* this is only valid for legendary + * wep, 0~3 for key id. (tx key index) + */ + union Keytype dot11DefKey[4]; /* this is only valid for def. key */ + u32 dot11DefKeylen[4]; + + u32 dot118021XGrpPrivacy; /* specify the privacy algthm. + * used for Grp key + */ + u32 dot118021XGrpKeyid; /* key id used for Grp Key + * (tx key index) + */ + union Keytype dot118021XGrpKey[4];/* 802.1x Grp Key, inx0 and inx1 */ + union Keytype dot118021XGrptxmickey[4]; + union Keytype dot118021XGrprxmickey[4]; + union pn48 dot11Grptxpn; /* PN48 used for Grp Key xmit.*/ + union pn48 dot11Grprxpn; /* PN48 used for Grp Key recv.*/ + +#ifdef CONFIG_8723AU_AP_MODE + /* extend security capabilities for AP_MODE */ + unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ + unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ + unsigned int wpa_group_cipher; + unsigned int wpa2_group_cipher; + unsigned int wpa_pairwise_cipher; + unsigned int wpa2_pairwise_cipher; +#endif + + u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */ + int wps_ie_len; + u8 binstallGrpkey; + u8 busetkipkey; + u8 bcheck_grpkey; + u8 bgrpkey_handshake; + s32 hw_decrypted; + u32 ndisauthtype; /* enum ndis_802_11_auth_mode */ + u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */ + struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ + struct ndis_802_11_wep ndiswep; + u8 assoc_info[600]; + u8 szofcapability[256]; /* for wpa2 usage */ + u8 oidassociation[512]; /* for wpa/wpa2 usage */ + u8 authenticator_ie[256]; /* store ap security information element */ + u8 supplicant_ie[256]; /* store sta security information element */ + + /* for tkip countermeasure */ + unsigned long last_mic_err_time; + u8 btkip_countermeasure; + u8 btkip_wait_report; + unsigned long btkip_countermeasure_time; + + /* For WPA2 Pre-Authentication. */ + struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE]; + u8 PMKIDIndex; + u8 bWepDefaultKeyIdxSet; +}; + +struct sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +}; + +#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ +do {\ + switch (psecuritypriv->dot11AuthAlgrthm) {\ + case dot11AuthAlgrthm_Open:\ + case dot11AuthAlgrthm_Shared:\ + case dot11AuthAlgrthm_Auto:\ + encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\ + break;\ + case dot11AuthAlgrthm_8021X:\ + if (bmcst)\ + encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\ + else\ + encry_algo = (u8)psta->dot118021XPrivacy;\ + break;\ + } \ +} while (0) + +#define GET_TKIP_PN(iv, dot11txpn)\ +do {\ + dot11txpn._byte_.TSC0 = iv[2];\ + dot11txpn._byte_.TSC1 = iv[0];\ + dot11txpn._byte_.TSC2 = iv[4];\ + dot11txpn._byte_.TSC3 = iv[5];\ + dot11txpn._byte_.TSC4 = iv[6];\ + dot11txpn._byte_.TSC5 = iv[7];\ +} while (0) + +#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1))) +#define ROR32(A, n) ROL32((A), 32-(n)) + +struct mic_data { + u32 K0, K1; /* Key */ + u32 L, R; /* Current state */ + u32 M; /* Message accumulator (single word) */ + u32 nBytesInM; /* # bytes in M */ +}; + +extern const u32 Te0[256]; +extern const u32 Te1[256]; +extern const u32 Te2[256]; +extern const u32 Te3[256]; +extern const u32 Te4[256]; +extern const u32 Td0[256]; +extern const u32 Td1[256]; +extern const u32 Td2[256]; +extern const u32 Td3[256]; +extern const u32 Td4[256]; +extern const u32 rcon[10]; +extern const u8 Td4s[256]; +extern const u8 rcons[10]; + +#define RCON(i) (rcons[(i)] << 24) + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) +#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) +#define TE3(i) rotr(Te0[(i) & 0xff], 24) +#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) +#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) +#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) +#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) +#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) +#define TD3(i) rotr(Td0[(i) & 0xff], 24) +#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) +#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) +#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) +#define TD44(i) (Td4s[(i) & 0xff]) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) rotr(Td0[(i) & 0xff], 8) +#define TD2_(i) rotr(Td0[(i) & 0xff], 16) +#define TD3_(i) rotr(Td0[(i) & 0xff], 24) + +#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ + ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) + +#define PUTU32(ct, st) { \ +(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ +(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) + +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +/* ===== start - public domain SHA256 implementation ===== */ + +/* This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. */ + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Various logical functions */ +#define RORc(x, y) \ +(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ +((unsigned long)(x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +void rtw_secmicsetkey23a(struct mic_data *pmicdata, u8 *key); +void rtw_secmicappend23abyte23a(struct mic_data *pmicdata, u8 b); +void rtw_secmicappend23a(struct mic_data *pmicdata, u8 *src, u32 nbBytes); +void rtw_secgetmic23a(struct mic_data *pmicdata, u8 *dst); + +void rtw_seccalctkipmic23a(u8 *key, u8 *header, u8 *data, u32 data_len, + u8 *Miccode, u8 priorityi); + +u32 rtw_aes_encrypt23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +u32 rtw_tkip_encrypt23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +void rtw_wep_encrypt23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +u32 rtw_aes_decrypt23a(struct rtw_adapter *padapter, + struct recv_frame *precvframe); +u32 rtw_tkip_decrypt23a(struct rtw_adapter *padapter, + struct recv_frame *precvframe); +void rtw_wep_decrypt23a(struct rtw_adapter *padapter, struct recv_frame *precvframe); + +void rtw_use_tkipkey_handler23a(void *FunctionContext); + +#endif /* __RTL871X_SECURITY_H_ */ diff --git a/drivers/staging/rtl8723au/include/rtw_sreset.h b/drivers/staging/rtl8723au/include/rtw_sreset.h new file mode 100644 index 000000000000..4c523722dd14 --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_sreset.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_SRESET_C_ +#define _RTW_SRESET_C_ + +#include +#include + +enum { + SRESET_TGP_NULL = 0, + SRESET_TGP_XMIT_STATUS = 1, + SRESET_TGP_LINK_STATUS = 2, +}; + +struct sreset_priv { + struct mutex silentreset_mutex; + u8 silent_reset_inprogress; + u8 Wifi_Error_Status; + unsigned long last_tx_time; + unsigned long last_tx_complete_time; + + s32 dbg_trigger_point; +}; + +#include + +#define WIFI_STATUS_SUCCESS 0 +#define USB_VEN_REQ_CMD_FAIL BIT0 +#define USB_READ_PORT_FAIL BIT1 +#define USB_WRITE_PORT_FAIL BIT2 +#define WIFI_MAC_TXDMA_ERROR BIT3 +#define WIFI_TX_HANG BIT4 +#define WIFI_RX_HANG BIT5 +#define WIFI_IF_NOT_EXIST BIT6 + +void sreset_init_value23a(struct rtw_adapter *padapter); +void sreset_reset_value23a(struct rtw_adapter *padapter); +u8 sreset_get_wifi_status23a(struct rtw_adapter *padapter); +void sreset_set_wifi_error_status23a(struct rtw_adapter *padapter, u32 status); +void sreset_set_trigger_point(struct rtw_adapter *padapter, s32 tgp); +bool sreset_inprogress(struct rtw_adapter *padapter); +void sreset_reset(struct rtw_adapter *padapter); + +#endif diff --git a/drivers/staging/rtl8723au/include/rtw_version.h b/drivers/staging/rtl8723au/include/rtw_version.h new file mode 100644 index 000000000000..c947733a3e3e --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_version.h @@ -0,0 +1 @@ +#define DRIVERVERSION "v4.1.6_7336.20130426" diff --git a/drivers/staging/rtl8723au/include/rtw_xmit.h b/drivers/staging/rtl8723au/include/rtw_xmit.h new file mode 100644 index 000000000000..65a33a07c8ee --- /dev/null +++ b/drivers/staging/rtl8723au/include/rtw_xmit.h @@ -0,0 +1,407 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _RTW_XMIT_H_ +#define _RTW_XMIT_H_ + +#include +#include + +#define MAX_XMITBUF_SZ 2048 +#define NR_XMITBUFF 4 + +#define XMITBUF_ALIGN_SZ 512 + +/* xmit extension buff defination */ +#define MAX_XMIT_EXTBUF_SZ 1536 +#define NR_XMIT_EXTBUFF 32 + +#define MAX_NUMBLKS 1 + +#define XMIT_VO_QUEUE 0 +#define XMIT_VI_QUEUE 1 +#define XMIT_BE_QUEUE 2 +#define XMIT_BK_QUEUE 3 + +#define VO_QUEUE_INX 0 +#define VI_QUEUE_INX 1 +#define BE_QUEUE_INX 2 +#define BK_QUEUE_INX 3 +#define BCN_QUEUE_INX 4 +#define MGT_QUEUE_INX 5 +#define HIGH_QUEUE_INX 6 +#define TXCMD_QUEUE_INX 7 + +#define HW_QUEUE_ENTRY 8 + +#define WEP_IV(pattrib_iv, dot11txpn, keyidx) \ +do { \ + pattrib_iv[0] = dot11txpn._byte_.TSC0; \ + pattrib_iv[1] = dot11txpn._byte_.TSC1; \ + pattrib_iv[2] = dot11txpn._byte_.TSC2; \ + pattrib_iv[3] = ((keyidx & 0x3) << 6); \ + dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 : \ + (dot11txpn.val+1); \ +} while (0) + +#define TKIP_IV(pattrib_iv, dot11txpn, keyidx) \ +do { \ + pattrib_iv[0] = dot11txpn._byte_.TSC1; \ + pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f; \ + pattrib_iv[2] = dot11txpn._byte_.TSC0; \ + pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6); \ + pattrib_iv[4] = dot11txpn._byte_.TSC2; \ + pattrib_iv[5] = dot11txpn._byte_.TSC3; \ + pattrib_iv[6] = dot11txpn._byte_.TSC4; \ + pattrib_iv[7] = dot11txpn._byte_.TSC5; \ + dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : \ + (dot11txpn.val+1); \ +} while (0) + +#define AES_IV(pattrib_iv, dot11txpn, keyidx)\ +do { \ + pattrib_iv[0] = dot11txpn._byte_.TSC0; \ + pattrib_iv[1] = dot11txpn._byte_.TSC1; \ + pattrib_iv[2] = 0; \ + pattrib_iv[3] = BIT(5) | ((keyidx & 0x3) << 6); \ + pattrib_iv[4] = dot11txpn._byte_.TSC2; \ + pattrib_iv[5] = dot11txpn._byte_.TSC3; \ + pattrib_iv[6] = dot11txpn._byte_.TSC4; \ + pattrib_iv[7] = dot11txpn._byte_.TSC5; \ + dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : \ + (dot11txpn.val+1); \ +} while (0) + +#define HWXMIT_ENTRY 4 + +#define TXDESC_SIZE 32 + +#define PACKET_OFFSET_SZ 8 +#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ) + +struct tx_desc { + /* DWORD 0 */ + unsigned int txdw0; + unsigned int txdw1; + unsigned int txdw2; + unsigned int txdw3; + unsigned int txdw4; + unsigned int txdw5; + unsigned int txdw6; + unsigned int txdw7; +}; + +union txdesc { + struct tx_desc txdesc; + unsigned int value[TXDESC_SIZE>>2]; +}; + +struct hw_xmit { + struct rtw_queue *sta_queue; + int accnt; +}; + +/* reduce size */ +struct pkt_attrib { + u8 type; + u8 subtype; + u8 bswenc; + u8 dhcp_pkt; + u16 ether_type; + u16 seqnum; + u16 pkt_hdrlen; /* the original 802.3 pkt header len */ + u16 hdrlen; /* the WLAN Header Len */ + u32 pktlen; /* the original 802.3 pkt raw_data len */ + u32 last_txcmdsz; + u8 nr_frags; + u8 encrypt; /* when 0 indicate no encrypt. */ + u8 iv_len; + u8 icv_len; + u8 iv[18]; + u8 icv[16]; + u8 priority; + u8 ack_policy; + u8 mac_id; + u8 vcs_mode; /* virtual carrier sense method */ + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 ta[ETH_ALEN]; + u8 ra[ETH_ALEN]; + u8 key_idx; + u8 qos_en; + u8 ht_en; + u8 raid;/* rate adpative id */ + u8 bwmode; + u8 ch_offset;/* PRIME_CHNL_OFFSET */ + u8 sgi;/* short GI */ + u8 ampdu_en;/* tx ampdu enable */ + u8 mdata;/* more data bit */ + u8 pctrl;/* per packet txdesc control enable */ + u8 triggered;/* for ap mode handling Power Saving sta */ + u8 qsel; + u8 eosp; + u8 rate; + u8 retry_ctrl; + struct sta_info *psta; +}; + +#define WLANHDR_OFFSET 64 + +#define NULL_FRAMETAG 0x0 +#define DATA_FRAMETAG 0x01 +#define L2_FRAMETAG 0x02 +#define MGNT_FRAMETAG 0x03 +#define AMSDU_FRAMETAG 0x04 + +#define EII_FRAMETAG 0x05 +#define IEEE8023_FRAMETAG 0x06 + +#define MP_FRAMETAG 0x07 + +#define TXAGG_FRAMETAG 0x08 + +struct submit_ctx { + u32 timeout_ms; /* <0: not synchronous, 0: wait forever, + * >0: up to ms waiting + */ + int status; /* status for operation */ + struct completion done; +}; + +enum { + RTW_SCTX_SUBMITTED = -1, + RTW_SCTX_DONE_SUCCESS = 0, + RTW_SCTX_DONE_UNKNOWN, + RTW_SCTX_DONE_TIMEOUT, + RTW_SCTX_DONE_BUF_ALLOC, + RTW_SCTX_DONE_BUF_FREE, + RTW_SCTX_DONE_WRITE_PORT_ERR, + RTW_SCTX_DONE_TX_DESC_NA, + RTW_SCTX_DONE_TX_DENY, + RTW_SCTX_DONE_CCX_PKT_FAIL, + RTW_SCTX_DONE_DRV_STOP, + RTW_SCTX_DONE_DEV_REMOVE, +}; + +void rtw_sctx_init23a(struct submit_ctx *sctx, int timeout_ms); +int rtw_sctx_wait23a(struct submit_ctx *sctx); +void rtw23a_sctx_done_err(struct submit_ctx **sctx, int status); +void rtw_sctx_done23a(struct submit_ctx **sctx); + +struct xmit_buf { + struct list_head list, list2; + struct rtw_adapter *padapter; + + u8 *pallocated_buf; + u8 *pbuf; + void *priv_data; + + u16 ext_tag; /* 0: Normal xmitbuf, 1: extension xmitbuf. */ + u16 flags; + u32 alloc_sz; + u32 len; + struct submit_ctx *sctx; + u32 ff_hwaddr; + struct urb *pxmit_urb[8]; + u8 bpending[8]; + int last[8]; +#if defined(DBG_XMIT_BUF) || defined(DBG_XMIT_BUF_EXT) + u8 no; +#endif +}; + +struct xmit_frame { + struct list_head list; + struct pkt_attrib attrib; + struct sk_buff *pkt; + int frame_tag; + struct rtw_adapter *padapter; + u8 *buf_addr; + struct xmit_buf *pxmitbuf; + + s8 pkt_offset; + + u8 ack_report; + + u8 ext_tag; /* 0:data, 1:mgmt */ +}; + +struct tx_servq { + struct list_head tx_pending; + struct rtw_queue sta_pending; + int qcnt; +}; + +struct sta_xmit_priv { + spinlock_t lock; + int option; + int apsd_setting; /* When bit mask is on, the associated edca + * queue supports APSD. + */ + struct tx_servq be_q; /* priority == 0,3 */ + struct tx_servq bk_q; /* priority == 1,2 */ + struct tx_servq vi_q; /* priority == 4,5 */ + struct tx_servq vo_q; /* priority == 6,7 */ + struct list_head legacy_dz; + struct list_head apsd; + u16 txseq_tid[16]; +}; + +struct hw_txqueue { + volatile int head; + volatile int tail; + volatile int free_sz; /* in units of 64 bytes */ + volatile int free_cmdsz; + volatile int txsz[8]; + uint ff_hwaddr; + uint cmd_hwaddr; + int ac_tag; +}; + +struct agg_pkt_info { + u16 offset; + u16 pkt_len; +}; + +struct xmit_priv { + spinlock_t lock; + + struct semaphore xmit_sema; + struct semaphore terminate_xmitthread_sema; + + struct rtw_queue be_pending; + struct rtw_queue bk_pending; + struct rtw_queue vi_pending; + struct rtw_queue vo_pending; + struct rtw_queue bm_pending; + + u8 *pallocated_frame_buf; + u8 *pxmit_frame_buf; + uint free_xmitframe_cnt; + struct rtw_queue free_xmit_queue; + + u8 *xframe_ext_alloc_addr; + u8 *xframe_ext; + uint free_xframe_ext_cnt; + struct rtw_queue free_xframe_ext_queue; + + uint frag_len; + + struct rtw_adapter *adapter; + + u8 vcs_setting; + u8 vcs; + u8 vcs_type; + + u64 tx_bytes; + u64 tx_pkts; + u64 tx_drop; + u64 last_tx_bytes; + u64 last_tx_pkts; + + struct hw_xmit *hwxmits; + u8 hwxmit_entry; + + u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength from + * large to small. it's value is 0->vo, 1->vi, + * 2->be, 3->bk. + */ + + struct semaphore tx_retevt;/* all tx return event; */ + u8 txirp_cnt;/* */ + + struct tasklet_struct xmit_tasklet; + /* per AC pending irp */ + int beq_cnt; + int bkq_cnt; + int viq_cnt; + int voq_cnt; + + struct rtw_queue free_xmitbuf_queue; + struct list_head xmitbuf_list; /* track buffers for cleanup */ + struct rtw_queue pending_xmitbuf_queue; + uint free_xmitbuf_cnt; + + struct rtw_queue free_xmit_extbuf_queue; + struct list_head xmitextbuf_list; /* track buffers for cleanup */ + uint free_xmit_extbuf_cnt; + + u16 nqos_ssn; + int ack_tx; + struct mutex ack_tx_mutex; + struct submit_ctx ack_tx_ops; + spinlock_t lock_sctx; +}; + +struct xmit_buf *rtw_alloc_xmitbuf23a_ext(struct xmit_priv *pxmitpriv); +s32 rtw_free_xmitbuf_ext23a(struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf); + +struct xmit_buf *rtw_alloc_xmitbuf23a(struct xmit_priv *pxmitpriv); +s32 rtw_free_xmitbuf23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); + +void rtw_count_tx_stats23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe, int sz); +void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len); +s32 rtw_make_wlanhdr23a(struct rtw_adapter *padapter, u8 *hdr, + struct pkt_attrib *pattrib); +s32 rtw_put_snap23a(u8 *data, u16 h_proto); +struct xmit_frame *rtw_alloc_xmitframe23a(struct xmit_priv *pxmitpriv); +struct xmit_frame *rtw_alloc_xmitframe23a_ext(struct xmit_priv *pxmitpriv); +struct xmit_frame *rtw_alloc_xmitframe23a_once(struct xmit_priv *pxmitpriv); +s32 rtw_free_xmitframe23a(struct xmit_priv *pxmitpriv, + struct xmit_frame *pxmitframe); +void rtw_free_xmitframe_queue23a(struct xmit_priv *pxmitpriv, struct rtw_queue *pframequeue); +struct tx_servq *rtw_get_sta_pending23a(struct rtw_adapter *padapter, + struct sta_info *psta, int up, u8 *ac); +s32 rtw_xmitframe_enqueue23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +struct xmit_frame *rtw_dequeue_xframe23a(struct xmit_priv *pxmitpriv, + struct hw_xmit *phwxmit_i, int entry); +s32 rtw_xmit23a_classifier(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +u32 rtw_calculate_wlan_pkt_size_by_attribue23a(struct pkt_attrib *pattrib); +#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue23a(&f->attrib) +s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, + struct xmit_frame *pxmitframe); +s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); +void _rtw_init_sta_xmit_priv23a(struct sta_xmit_priv *psta_xmitpriv); + +s32 rtw_txframes_pending23a(struct rtw_adapter *padapter); +s32 rtw_txframes_sta_ac_pending23a(struct rtw_adapter *padapter, + struct pkt_attrib *pattrib); +void rtw_init_hwxmits23a(struct hw_xmit *phwxmit, int entry); +s32 _rtw_init_xmit_priv23a(struct xmit_priv *pxmitpriv, + struct rtw_adapter *padapter); +void _rtw_free_xmit_priv23a(struct xmit_priv *pxmitpriv); +void rtw_alloc_hwxmits23a(struct rtw_adapter *padapter); +void rtw_free_hwxmits23a(struct rtw_adapter *padapter); +int rtw_xmit23a(struct rtw_adapter *padapter, struct sk_buff *pkt); +#if defined(CONFIG_8723AU_AP_MODE) +int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe); +void stop_sta_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta); +void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta); +void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter, + struct sta_info *psta); +#endif +u8 qos_acm23a(u8 acm_mask, u8 priority); +u32 rtw_get_ff_hwaddr23a(struct xmit_frame *pxmitframe); +int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms); +void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status); + +/* include after declaring struct xmit_buf, in order to avoid warning */ +#include + +#endif /* _RTL871X_XMIT_H_ */ diff --git a/drivers/staging/rtl8723au/include/sta_info.h b/drivers/staging/rtl8723au/include/sta_info.h new file mode 100644 index 000000000000..8af98ee77b07 --- /dev/null +++ b/drivers/staging/rtl8723au/include/sta_info.h @@ -0,0 +1,396 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __STA_INFO_H_ +#define __STA_INFO_H_ + +#include +#include +#include + +#define IBSS_START_MAC_ID 2 +#define NUM_STA 32 +#define NUM_ACL 16 + + +/* if mode ==0, then the sta is allowed once the addr is hit. */ +/* if mode ==1, then the sta is rejected once the addr is non-hit. */ +struct rtw_wlan_acl_node { + struct list_head list; + u8 addr[ETH_ALEN]; + u8 valid; +}; + +/* mode=0, disable */ +/* mode=1, accept unless in deny list */ +/* mode=2, deny unless in accept list */ +struct wlan_acl_pool { + int mode; + int num; + struct rtw_wlan_acl_node aclnode[NUM_ACL]; + struct rtw_queue acl_node_q; +}; + +struct rssi_sta { + s32 UndecoratedSmoothedPWDB; + s32 UndecoratedSmoothedCCK; + s32 UndecoratedSmoothedOFDM; + u64 PacketMap; + u8 ValidBit; +}; + +struct stainfo_stats { + u64 rx_mgnt_pkts; + u64 rx_beacon_pkts; + u64 rx_probereq_pkts; + u64 rx_probersp_pkts; + u64 rx_probersp_bm_pkts; + u64 rx_probersp_uo_pkts; + u64 rx_ctrl_pkts; + u64 rx_data_pkts; + + u64 last_rx_mgnt_pkts; + u64 last_rx_beacon_pkts; + u64 last_rx_probereq_pkts; + u64 last_rx_probersp_pkts; + u64 last_rx_probersp_bm_pkts; + u64 last_rx_probersp_uo_pkts; + u64 last_rx_ctrl_pkts; + u64 last_rx_data_pkts; + + u64 rx_bytes; + u64 rx_drops; + + u64 tx_pkts; + u64 tx_bytes; + u64 tx_drops; + +}; + +struct sta_info { + spinlock_t lock; + struct list_head list; /* free_sta_queue */ + struct list_head hash_list; /* sta_hash */ + struct rtw_adapter *padapter; + + struct sta_xmit_priv sta_xmitpriv; + struct sta_recv_priv sta_recvpriv; + + struct rtw_queue sleep_q; + unsigned int sleepq_len; + + uint state; + uint aid; + uint mac_id; + uint qos_option; + u8 hwaddr[ETH_ALEN]; + + uint ieee8021x_blocked; /* 0: allowed, 1:blocked */ + uint dot118021XPrivacy; /* aes, tkip... */ + union Keytype dot11tkiptxmickey; + union Keytype dot11tkiprxmickey; + union Keytype dot118021x_UncstKey; + union pn48 dot11txpn; /* PN48 used for Unicast xmit. */ + union pn48 dot11rxpn; /* PN48 used for Unicast recv. */ + + + u8 bssrateset[16]; + u32 bssratelen; + s32 rssi; + s32 signal_quality; + + u8 cts2self; + u8 rtsen; + + u8 raid; + u8 init_rate; + u32 ra_mask; + u8 wireless_mode; /* NETWORK_TYPE */ + struct stainfo_stats sta_stats; + + /* for A-MPDU TX, ADDBA timeout check */ + struct timer_list addba_retry_timer; + + /* for A-MPDU Rx reordering buffer control */ + struct recv_reorder_ctrl recvreorder_ctrl[16]; + + /* for A-MPDU Tx */ + /* unsigned char ampdu_txen_bitmap; */ + u16 BA_starting_seqctrl[16]; + + struct ht_priv htpriv; + + /* Notes: */ + /* STA_Mode: */ + /* curr_network(mlme_priv/security_priv/qos/ht) + sta_info: (STA & AP) CAP/INFO */ + /* scan_q: AP CAP/INFO */ + + /* AP_Mode: */ + /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */ + /* sta_info: (AP & STA) CAP/INFO */ + +#ifdef CONFIG_8723AU_AP_MODE + + struct list_head asoc_list; + struct list_head auth_list; + + unsigned int expire_to; + unsigned int auth_seq; + unsigned int authalg; + unsigned char chg_txt[128]; + + u16 capability; + int flags; + + int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ + int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ + int wpa_group_cipher; + int wpa2_group_cipher; + int wpa_pairwise_cipher; + int wpa2_pairwise_cipher; + + u8 bpairwise_key_installed; + + u8 wpa_ie[32]; + + u8 nonerp_set; + u8 no_short_slot_time_set; + u8 no_short_preamble_set; + u8 no_ht_gf_set; + u8 no_ht_set; + u8 ht_20mhz_set; + + unsigned int tx_ra_bitmap; + u8 qos_info; + + u8 max_sp_len; + u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */ + u8 uapsd_be; + u8 uapsd_vi; + u8 uapsd_vo; + + u8 has_legacy_ac; + unsigned int sleepq_ac_len; + +#ifdef CONFIG_8723AU_P2P + /* p2p priv data */ + u8 is_p2p_device; + u8 p2p_status_code; + + /* p2p client info */ + u8 dev_addr[ETH_ALEN]; + u8 dev_cap; + u16 config_methods; + u8 primary_dev_type[8]; + u8 num_of_secdev_type; + u8 secdev_types_list[32];/* 32/8 == 4; */ + u16 dev_name_len; + u8 dev_name[32]; +#endif /* CONFIG_8723AU_P2P */ + + u8 keep_alive_trycnt; + +#endif /* CONFIG_8723AU_AP_MODE */ + + u8 *passoc_req; + u32 assoc_req_len; + + /* for DM */ + struct rssi_sta rssi_stat; + + /* */ + /* ================ODM Relative Info======================= */ + /* Please be care, dont declare too much structure here. It will cost memory * STA support num. */ + /* */ + /* */ + /* 2011/10/20 MH Add for ODM STA info. */ + /* */ + /* Driver Write */ + u8 bValid; /* record the sta status link or not? */ + u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ + u8 rssi_level; /* for Refresh RA mask */ + /* ODM Write */ + /* 1 PHY_STATUS_INFO */ + u8 RSSI_Path[4]; /* */ + u8 RSSI_Ave; + u8 RXEVM[4]; + u8 RXSNR[4]; + + /* ODM Write */ + /* 1 TX_INFO (may changed by IC) */ + /* ================ODM Relative Info======================= */ + /* */ + + /* To store the sequence number of received management frame */ + u16 RxMgmtFrameSeqNum; +}; + +#define sta_rx_pkts(sta) \ + (sta->sta_stats.rx_mgnt_pkts \ + + sta->sta_stats.rx_ctrl_pkts \ + + sta->sta_stats.rx_data_pkts) + +#define sta_last_rx_pkts(sta) \ + (sta->sta_stats.last_rx_mgnt_pkts \ + + sta->sta_stats.last_rx_ctrl_pkts \ + + sta->sta_stats.last_rx_data_pkts) + +#define sta_rx_data_pkts(sta) \ + (sta->sta_stats.rx_data_pkts) + +#define sta_last_rx_data_pkts(sta) \ + (sta->sta_stats.last_rx_data_pkts) + +#define sta_rx_mgnt_pkts(sta) \ + (sta->sta_stats.rx_mgnt_pkts) + +#define sta_last_rx_mgnt_pkts(sta) \ + (sta->sta_stats.last_rx_mgnt_pkts) + +#define sta_rx_beacon_pkts(sta) \ + (sta->sta_stats.rx_beacon_pkts) + +#define sta_last_rx_beacon_pkts(sta) \ + (sta->sta_stats.last_rx_beacon_pkts) + +#define sta_rx_probereq_pkts(sta) \ + (sta->sta_stats.rx_probereq_pkts) + +#define sta_last_rx_probereq_pkts(sta) \ + (sta->sta_stats.last_rx_probereq_pkts) + +#define sta_rx_probersp_pkts(sta) \ + (sta->sta_stats.rx_probersp_pkts) + +#define sta_last_rx_probersp_pkts(sta) \ + (sta->sta_stats.last_rx_probersp_pkts) + +#define sta_rx_probersp_bm_pkts(sta) \ + (sta->sta_stats.rx_probersp_bm_pkts) + +#define sta_last_rx_probersp_bm_pkts(sta) \ + (sta->sta_stats.last_rx_probersp_bm_pkts) + +#define sta_rx_probersp_uo_pkts(sta) \ + (sta->sta_stats.rx_probersp_uo_pkts) + +#define sta_last_rx_probersp_uo_pkts(sta) \ + (sta->sta_stats.last_rx_probersp_uo_pkts) + +#define sta_update_last_rx_pkts(sta) \ + do { \ + sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \ + sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \ + sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \ + sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \ + sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \ + sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \ + sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \ + sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \ + } while (0) + +#define STA_RX_PKTS_ARG(sta) \ + sta->sta_stats.rx_mgnt_pkts \ + , sta->sta_stats.rx_ctrl_pkts \ + , sta->sta_stats.rx_data_pkts + +#define STA_LAST_RX_PKTS_ARG(sta) \ + sta->sta_stats.last_rx_mgnt_pkts, \ + sta->sta_stats.last_rx_ctrl_pkts, \ + sta->sta_stats.last_rx_data_pkts + +#define STA_RX_PKTS_DIFF_ARG(sta) \ + sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts, \ + sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts, \ + sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts + +#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)" + +struct sta_priv { + u8 *pallocated_stainfo_buf; + u8 *pstainfo_buf; + struct rtw_queue free_sta_queue; + + spinlock_t sta_hash_lock; + struct list_head sta_hash[NUM_STA]; + int asoc_sta_count; + struct rtw_queue sleep_q; + struct rtw_queue wakeup_q; + + struct rtw_adapter *padapter; + + +#ifdef CONFIG_8723AU_AP_MODE + struct list_head asoc_list; + struct list_head auth_list; + spinlock_t asoc_list_lock; + spinlock_t auth_list_lock; + u8 asoc_list_cnt; + u8 auth_list_cnt; + + unsigned int auth_to; /* sec, time to expire in authenticating. */ + unsigned int assoc_to; /* sec, time to expire before associating. */ + unsigned int expire_to; /* sec , time to expire after associated. */ + + /* pointers to STA info; based on allocated AID or NULL if AID free + * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 + * and so on + */ + struct sta_info *sta_aid[NUM_STA]; + + u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap + * for sleeping sta. */ + u16 tim_bitmap;/* only support 15 stations, + * aid=0~15 mapping bit0~bit15 */ + + u16 max_num_sta; + + struct wlan_acl_pool acl_list; +#endif +}; + +static inline u32 wifi_mac_hash(u8 *mac) +{ + u32 x; + + x = mac[0]; + x = (x << 2) ^ mac[1]; + x = (x << 2) ^ mac[2]; + x = (x << 2) ^ mac[3]; + x = (x << 2) ^ mac[4]; + x = (x << 2) ^ mac[5]; + + x ^= x >> 8; + x = x & (NUM_STA - 1); + + return x; +} + +u32 _rtw_init_sta_priv23a(struct sta_priv *pstapriv); +u32 _rtw_free_sta_priv23a(struct sta_priv *pstapriv); + +#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0) +int rtw_stainfo_offset23a(struct sta_priv *stapriv, struct sta_info *sta); +struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv, + int offset); + +struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr); +u32 rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta); +void rtw_free_all_stainfo23a(struct rtw_adapter *padapter); +struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr); +u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter *padapter); +struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter); +u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr); + +#endif /* _STA_INFO_H_ */ diff --git a/drivers/staging/rtl8723au/include/usb_hal.h b/drivers/staging/rtl8723au/include/usb_hal.h new file mode 100644 index 000000000000..4edec3b539b7 --- /dev/null +++ b/drivers/staging/rtl8723au/include/usb_hal.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __USB_HAL_H__ +#define __USB_HAL_H__ + +int rtl8723au_set_hal_ops(struct rtw_adapter *padapter); + +#endif /* __USB_HAL_H__ */ diff --git a/drivers/staging/rtl8723au/include/usb_ops.h b/drivers/staging/rtl8723au/include/usb_ops.h new file mode 100644 index 000000000000..55d1380f9036 --- /dev/null +++ b/drivers/staging/rtl8723au/include/usb_ops.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __USB_OPS_H_ +#define __USB_OPS_H_ + +#include +#include +#include +#include + +#define REALTEK_USB_VENQT_READ 0xC0 +#define REALTEK_USB_VENQT_WRITE 0x40 +#define REALTEK_USB_VENQT_CMD_REQ 0x05 +#define REALTEK_USB_VENQT_CMD_IDX 0x00 + +enum { + VENDOR_WRITE = 0x00, + VENDOR_READ = 0x01, +}; + +#define ALIGNMENT_UNIT 16 +#define MAX_VENDOR_REQ_CMD_SIZE 254 /* 8188cu SIE Support */ +#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE +ALIGNMENT_UNIT) + +#define rtw_usb_control_msg(dev, pipe, request, requesttype, value, \ + index, data, size, timeout_ms) \ + usb_control_msg((dev), (pipe), (request), (requesttype), \ + (value), (index), (data), (size), (timeout_ms)) +#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \ + usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), \ + (timeout_ms)) + +void rtl8723au_set_hw_type(struct rtw_adapter *padapter); +#define hal_set_hw_type rtl8723au_set_hw_type + +void rtl8723au_set_intf_ops(struct _io_ops *pops); +#define usb_set_intf_ops rtl8723au_set_intf_ops + +void rtl8723au_recv_tasklet(void *priv); + +void rtl8723au_xmit_tasklet(void *priv); + +/* Increase and check if the continual_urb_error of this @param dvobjprive is + * larger than MAX_CONTINUAL_URB_ERR. Return result + */ +static inline int rtw_inc_and_chk_continual_urb_error(struct dvobj_priv *dvobj) +{ + int ret = false; + int value; + + value = atomic_inc_return(&dvobj->continual_urb_error); + if (value > MAX_CONTINUAL_URB_ERR) { + DBG_8723A("[dvobj:%p][ERROR] continual_urb_error:%d > %d\n", + dvobj, value, MAX_CONTINUAL_URB_ERR); + ret = true; + } + return ret; +} + +/* Set the continual_urb_error of this @param dvobjprive to 0 */ +static inline void rtw_reset_continual_urb_error(struct dvobj_priv *dvobj) +{ + atomic_set(&dvobj->continual_urb_error, 0); +} + +#define USB_HIGH_SPEED_BULK_SIZE 512 +#define USB_FULL_SPEED_BULK_SIZE 64 + +static inline u8 rtw_usb_bulk_size_boundary(struct rtw_adapter *padapter, + int buf_len) +{ + u8 rst = true; + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + + if (pdvobjpriv->ishighspeed) + rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE) ? + true : false; + else + rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE) ? + true : false; + return rst; +} + + +#endif /* __USB_OPS_H_ */ diff --git a/drivers/staging/rtl8723au/include/usb_ops_linux.h b/drivers/staging/rtl8723au/include/usb_ops_linux.h new file mode 100644 index 000000000000..8f5c59eace5a --- /dev/null +++ b/drivers/staging/rtl8723au/include/usb_ops_linux.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __USB_OPS_LINUX_H__ +#define __USB_OPS_LINUX_H__ + +#define VENDOR_CMD_MAX_DATA_LEN 254 + +#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10/* ms */ +#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */ + +#define MAX_USBCTRL_VENDORREQ_TIMES 10 + +#define RTW_USB_BULKOUT_TIMEOUT 5000/* ms */ + +#define _usbctrl_vendorreq_async_callback(urb, regs) \ + _usbctrl_vendorreq_async_callback(urb) +#define usb_write_mem23a_complete(purb, regs) usb_write_mem23a_complete(purb) +#define usb_write_port23a_complete(purb, regs) usb_write_port23a_complete(purb) +#define usb_read_port_complete(purb, regs) usb_read_port_complete(purb) +#define usb_read_interrupt_complete(purb, regs) \ + usb_read_interrupt_complete(purb) + +unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr); + +void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); +void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); + +void usb_read_port_cancel23a(struct intf_hdl *pintfhdl); + +u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, + struct xmit_buf *wmem); +void usb_write_port23a_cancel(struct intf_hdl *pintfhdl); + +#endif diff --git a/drivers/staging/rtl8723au/include/usb_osintf.h b/drivers/staging/rtl8723au/include/usb_osintf.h new file mode 100644 index 000000000000..46087662834e --- /dev/null +++ b/drivers/staging/rtl8723au/include/usb_osintf.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __USB_OSINTF_H +#define __USB_OSINTF_H + +#include +#include +#include + +#define USBD_HALTED(_status) ((u32)(_status) >> 30 == 3) + +#endif diff --git a/drivers/staging/rtl8723au/include/usb_vendor_req.h b/drivers/staging/rtl8723au/include/usb_vendor_req.h new file mode 100644 index 000000000000..eb4508ef191e --- /dev/null +++ b/drivers/staging/rtl8723au/include/usb_vendor_req.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _USB_VENDOR_REQUEST_H_ +#define _USB_VENDOR_REQUEST_H_ + +/* 4 Set/Get Register related wIndex/Data */ +#define RT_USB_RESET_MASK_OFF 0 +#define RT_USB_RESET_MASK_ON 1 +#define RT_USB_SLEEP_MASK_OFF 0 +#define RT_USB_SLEEP_MASK_ON 1 +#define RT_USB_LDO_ON 1 +#define RT_USB_LDO_OFF 0 + +/* 4 Set/Get SYSCLK related wValue or Data */ +#define RT_USB_SYSCLK_32KHZ 0 +#define RT_USB_SYSCLK_40MHZ 1 +#define RT_USB_SYSCLK_60MHZ 2 + +#endif diff --git a/drivers/staging/rtl8723au/include/wifi.h b/drivers/staging/rtl8723au/include/wifi.h new file mode 100644 index 000000000000..b5034c6ef1dc --- /dev/null +++ b/drivers/staging/rtl8723au/include/wifi.h @@ -0,0 +1,707 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef _WIFI_H_ +#define _WIFI_H_ + +#define P80211CAPTURE_VERSION 0x80211001 + +/* This value is tested by WiFi 11n Test Plan 5.2.3. + * This test verifies the WLAN NIC can update the NAV through sending + * the CTS with large duration. + */ +#define WiFiNavUpperUs 30000 /* 30 ms */ + +enum WIFI_FRAME_TYPE { + WIFI_MGT_TYPE = (0), + WIFI_CTRL_TYPE = (BIT(2)), + WIFI_DATA_TYPE = (BIT(3)), + WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /* QoS Data */ +}; + +enum WIFI_FRAME_SUBTYPE { + /* below is for mgt frame */ + WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), + WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), + WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), + WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), + WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), + WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), + WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), + WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), + WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), + WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), + WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), + WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), + + /* below is for control frame */ + WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), + WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), + WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), + WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), + WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), + WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), + + /* below is for data frame */ + WIFI_DATA = (0 | WIFI_DATA_TYPE), + WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), + WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), + WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), + WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), + WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), + WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), + WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), + WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), +}; + + +enum WIFI_REG_DOMAIN { + DOMAIN_FCC = 1, + DOMAIN_IC = 2, + DOMAIN_ETSI = 3, + DOMAIN_SPAIN = 4, + DOMAIN_FRANCE = 5, + DOMAIN_MKK = 6, + DOMAIN_ISRAEL = 7, + DOMAIN_MKK1 = 8, + DOMAIN_MKK2 = 9, + DOMAIN_MKK3 = 10, + DOMAIN_MAX +}; + + +#define SetToDs(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS)) + +#define SetFrDs(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS)) + +#define get_tofr_ds(pframe) ((ieee80211_has_tods(pframe) << 1) | \ + ieee80211_has_fromds(pframe)) + +#define SetMFrag(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) + +#define ClearMFrag(pbuf) \ + (*(unsigned short *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))) + +#define SetRetry(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY)) + +#define SetPwrMgt(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM)) + +#define SetMData(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA)) + +#define SetPrivacy(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED)) + +#define SetFrameType(pbuf, type) \ + do { \ + *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ + *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \ + } while (0) + +#define SetFrameSubType(pbuf, type) \ + do { \ + *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ + *(unsigned short *)(pbuf) |= cpu_to_le16(type); \ + } while (0) + +#define GetTupleCache(pbuf) (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 22))) + +#define SetFragNum(pbuf, num) \ + do { \ + *(unsigned short *)((unsigned long)(pbuf) + 22) = \ + ((*(unsigned short *)((unsigned long)(pbuf) + 22)) & le16_to_cpu(~(0x000f))) | \ + cpu_to_le16(0x0f & (num)); \ + } while (0) + +#define SetSeqNum(pbuf, num) \ + do { \ + *(unsigned short *)((unsigned long)(pbuf) + 22) = \ + ((*(unsigned short *)((unsigned long)(pbuf) + 22)) & le16_to_cpu((unsigned short)0x000f)) | \ + le16_to_cpu((unsigned short)(0xfff0 & (num << 4))); \ + } while (0) + +#define SetDuration(pbuf, dur) \ + (*(unsigned short *)((unsigned long)(pbuf) + 2) = \ + cpu_to_le16(0xffff & (dur))) + +#define SetPriority(pbuf, tid) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(tid & 0xf)) + +#define SetEOSP(pbuf, eosp) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)) + +#define SetAckpolicy(pbuf, ack) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16((ack & 3) << 5)) + +#define SetAMsdu(pbuf, amsdu) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7)) + +#define GetAid(pbuf) \ + (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 2)) & \ + 0x3fff) + +#define GetTid(pbuf) \ + (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + \ + (((ieee80211_has_tods(pbuf)<<1) | \ + ieee80211_has_fromds(pbuf)) == 3 ? 30 : 24))) & 0x000f) + +static inline unsigned char *get_hdr_bssid(unsigned char *pframe) +{ + unsigned char *sa; + unsigned int to_fr_ds; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe; + + to_fr_ds = (ieee80211_has_tods(hdr->frame_control) << 1) | + ieee80211_has_fromds(hdr->frame_control); + + switch (to_fr_ds) { + case 0x00: /* ToDs=0, FromDs=0 */ + sa = hdr->addr3; + break; + case 0x01: /* ToDs=0, FromDs=1 */ + sa = hdr->addr2; + break; + case 0x02: /* ToDs=1, FromDs=0 */ + sa = hdr->addr1; + break; + case 0x03: /* ToDs=1, FromDs=1 */ + sa = hdr->addr1; + break; + default: + sa = NULL; /* */ + break; + } + return sa; +} + +/*----------------------------------------------------------------------------- + Below is for the security related definition +------------------------------------------------------------------------------*/ +#define _RESERVED_FRAME_TYPE_ 0 +#define _SKB_FRAME_TYPE_ 2 +#define _PRE_ALLOCMEM_ 1 +#define _PRE_ALLOCHDR_ 3 +#define _PRE_ALLOCLLCHDR_ 4 +#define _PRE_ALLOCICVHDR_ 5 +#define _PRE_ALLOCMICHDR_ 6 + +#define _SIFSTIME_ \ + ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) ? 16 : 10) +#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */ +#define _CRCLNG_ 4 + +#define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ +#define _ASOCRSP_IE_OFFSET_ 6 +#define _REASOCREQ_IE_OFFSET_ 10 +#define _REASOCRSP_IE_OFFSET_ 6 +#define _PROBEREQ_IE_OFFSET_ 0 +#define _PROBERSP_IE_OFFSET_ 12 +#define _AUTH_IE_OFFSET_ 6 +#define _DEAUTH_IE_OFFSET_ 0 +#define _BEACON_IE_OFFSET_ 12 +#define _PUBLIC_ACTION_IE_OFFSET_ 8 + +#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ + +#define _SSID_IE_ 0 +#define _SUPPORTEDRATES_IE_ 1 +#define _DSSET_IE_ 3 +#define _TIM_IE_ 5 +#define _IBSS_PARA_IE_ 6 +#define _COUNTRY_IE_ 7 +#define _CHLGETXT_IE_ 16 +#define _SUPPORTED_CH_IE_ 36 +#define _CH_SWTICH_ANNOUNCE_ 37 /* Secondary Channel Offset */ +#define _RSN_IE_2_ 48 +#define _SSN_IE_1_ 221 +#define _ERPINFO_IE_ 42 +#define _EXT_SUPPORTEDRATES_IE_ 50 + +#define _HT_CAPABILITY_IE_ 45 +#define _FTIE_ 55 +#define _TIMEOUT_ITVL_IE_ 56 +#define _SRC_IE_ 59 +#define _HT_EXTRA_INFO_IE_ 61 +#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ + + +#define EID_BSSCoexistence 72 /* 20/40 BSS Coexistence */ +#define EID_BSSIntolerantChlReport 73 +#define _RIC_Descriptor_IE_ 75 + +#define _LINK_ID_IE_ 101 +#define _CH_SWITCH_TIMING_ 104 +#define _PTI_BUFFER_STATUS_ 106 +#define _EXT_CAP_IE_ 127 +#define _VENDOR_SPECIFIC_IE_ 221 + +#define _RESERVED47_ 47 + +/* --------------------------------------------------------------------------- + Below is the fixed elements... +-----------------------------------------------------------------------------*/ +#define _AUTH_ALGM_NUM_ 2 +#define _AUTH_SEQ_NUM_ 2 +#define _BEACON_ITERVAL_ 2 +#define _CAPABILITY_ 2 +#define _CURRENT_APADDR_ 6 +#define _LISTEN_INTERVAL_ 2 +#define _ASOC_ID_ 2 +#define _STATUS_CODE_ 2 +#define _TIMESTAMP_ 8 + +#define AUTH_ODD_TO 0 +#define AUTH_EVEN_TO 1 + +#define WLAN_ETHCONV_ENCAP 1 +#define WLAN_ETHCONV_RFC1042 2 +#define WLAN_ETHCONV_8021h 3 + +#define cap_ESS BIT(0) +#define cap_IBSS BIT(1) +#define cap_CFPollable BIT(2) +#define cap_CFRequest BIT(3) +#define cap_Privacy BIT(4) +#define cap_ShortPremble BIT(5) +#define cap_PBCC BIT(6) +#define cap_ChAgility BIT(7) +#define cap_SpecMgmt BIT(8) +#define cap_QoS BIT(9) +#define cap_ShortSlot BIT(10) + +/*----------------------------------------------------------------------------- + Below is the definition for 802.11i / 802.1x +------------------------------------------------------------------------------*/ +#define _IEEE8021X_MGT_ 1 /* WPA */ +#define _IEEE8021X_PSK_ 2 /* WPA with pre-shared key */ + +/* +#define _NO_PRIVACY_ 0 +#define _WEP_40_PRIVACY_ 1 +#define _TKIP_PRIVACY_ 2 +#define _WRAP_PRIVACY_ 3 +#define _CCMP_PRIVACY_ 4 +#define _WEP_104_PRIVACY_ 5 +#define _WEP_WPA_MIXED_PRIVACY_ 6 WEP + WPA +*/ + +/*----------------------------------------------------------------------------- + Below is the definition for WMM +------------------------------------------------------------------------------*/ +#define _WMM_IE_Length_ 7 /* for WMM STA */ +#define _WMM_Para_Element_Length_ 24 + + +/*----------------------------------------------------------------------------- + Below is the definition for 802.11n +------------------------------------------------------------------------------*/ + +#define SetOrderBit(pbuf) \ + (*(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_)) + +#define GetOrderBit(pbuf) \ + (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0) + + +/* struct rtw_ieee80211_ht_cap - HT additional information + * + * This structure refers to "HT information element" as + * described in 802.11n draft section 7.3.2.53 + */ +struct ieee80211_ht_addt_info { + unsigned char control_chan; + unsigned char ht_param; + unsigned short operation_mode; + unsigned short stbc_param; + unsigned char basic_set[16]; +} __packed; + +struct HT_caps_element { + union { + struct { + unsigned short HT_caps_info; + unsigned char AMPDU_para; + unsigned char MCS_rate[16]; + unsigned short HT_ext_caps; + unsigned int Beamforming_caps; + unsigned char ASEL_caps; + } HT_cap_element; + unsigned char HT_cap[26]; + } u; +} __packed; + +struct HT_info_element { + unsigned char primary_channel; + unsigned char infos[5]; + unsigned char MCS_rate[16]; +} __packed; + +struct AC_param { + unsigned char ACI_AIFSN; + unsigned char CW; + unsigned short TXOP_limit; +} __packed; + +struct WMM_para_element { + unsigned char QoS_info; + unsigned char reserved; + struct AC_param ac_param[4]; +} __packed; + +struct ADDBA_request { + unsigned char dialog_token; + unsigned short BA_para_set; + unsigned short BA_timeout_value; + unsigned short BA_starting_seqctrl; +} __packed; + + +#define OP_MODE_PURE 0 +#define OP_MODE_MAY_BE_LEGACY_STAS 1 +#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 +#define OP_MODE_MIXED 3 + +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) +#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) +#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) +#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) +#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) +#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) + +#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ + ((u16) (0x0001 | 0x0002)) +#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 +#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) +#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) +#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) + +#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) +#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) +#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) +#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) +#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) +#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) + + + +/* ===============WPS Section=============== */ +/* For WPSv1.0 */ +#define WPSOUI 0x0050f204 +/* WPS attribute ID */ +#define WPS_ATTR_VER1 0x104A +#define WPS_ATTR_SIMPLE_CONF_STATE 0x1044 +#define WPS_ATTR_RESP_TYPE 0x103B +#define WPS_ATTR_UUID_E 0x1047 +#define WPS_ATTR_MANUFACTURER 0x1021 +#define WPS_ATTR_MODEL_NAME 0x1023 +#define WPS_ATTR_MODEL_NUMBER 0x1024 +#define WPS_ATTR_SERIAL_NUMBER 0x1042 +#define WPS_ATTR_PRIMARY_DEV_TYPE 0x1054 +#define WPS_ATTR_SEC_DEV_TYPE_LIST 0x1055 +#define WPS_ATTR_DEVICE_NAME 0x1011 +#define WPS_ATTR_CONF_METHOD 0x1008 +#define WPS_ATTR_RF_BANDS 0x103C +#define WPS_ATTR_DEVICE_PWID 0x1012 +#define WPS_ATTR_REQUEST_TYPE 0x103A +#define WPS_ATTR_ASSOCIATION_STATE 0x1002 +#define WPS_ATTR_CONFIG_ERROR 0x1009 +#define WPS_ATTR_VENDOR_EXT 0x1049 +#define WPS_ATTR_SELECTED_REGISTRAR 0x1041 + +/* Value of WPS attribute "WPS_ATTR_DEVICE_NAME */ +#define WPS_MAX_DEVICE_NAME_LEN 32 + +/* Value of WPS Request Type Attribute */ +#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00 +#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01 +#define WPS_REQ_TYPE_REGISTRAR 0x02 +#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR 0x03 + +/* Value of WPS Response Type Attribute */ +#define WPS_RESPONSE_TYPE_INFO_ONLY 0x00 +#define WPS_RESPONSE_TYPE_8021X 0x01 +#define WPS_RESPONSE_TYPE_REGISTRAR 0x02 +#define WPS_RESPONSE_TYPE_AP 0x03 + +/* Value of WPS WiFi Simple Configuration State Attribute */ +#define WPS_WSC_STATE_NOT_CONFIG 0x01 +#define WPS_WSC_STATE_CONFIG 0x02 + +/* Value of WPS Version Attribute */ +#define WPS_VERSION_1 0x10 + +/* Value of WPS Configuration Method Attribute */ +#define WPS_CONFIG_METHOD_FLASH 0x0001 +#define WPS_CONFIG_METHOD_ETHERNET 0x0002 +#define WPS_CONFIG_METHOD_LABEL 0x0004 +#define WPS_CONFIG_METHOD_DISPLAY 0x0008 +#define WPS_CONFIG_METHOD_E_NFC 0x0010 +#define WPS_CONFIG_METHOD_I_NFC 0x0020 +#define WPS_CONFIG_METHOD_NFC 0x0040 +#define WPS_CONFIG_METHOD_PBC 0x0080 +#define WPS_CONFIG_METHOD_KEYPAD 0x0100 +#define WPS_CONFIG_METHOD_VPBC 0x0280 +#define WPS_CONFIG_METHOD_PPBC 0x0480 +#define WPS_CONFIG_METHOD_VDISPLAY 0x2008 +#define WPS_CONFIG_METHOD_PDISPLAY 0x4008 + +/* Value of Category ID of WPS Primary Device Type Attribute */ +#define WPS_PDT_CID_DISPLAYS 0x0007 +#define WPS_PDT_CID_MULIT_MEDIA 0x0008 +#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA + +/* Value of Sub Category ID of WPS Primary Device Type Attribute */ +#define WPS_PDT_SCID_MEDIA_SERVER 0x0005 +#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER + +/* Value of Device Password ID */ +#define WPS_DPID_PIN 0x0000 +#define WPS_DPID_USER_SPEC 0x0001 +#define WPS_DPID_MACHINE_SPEC 0x0002 +#define WPS_DPID_REKEY 0x0003 +#define WPS_DPID_PBC 0x0004 +#define WPS_DPID_REGISTRAR_SPEC 0x0005 + +/* Value of WPS RF Bands Attribute */ +#define WPS_RF_BANDS_2_4_GHZ 0x01 +#define WPS_RF_BANDS_5_GHZ 0x02 + +/* Value of WPS Association State Attribute */ +#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00 +#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01 +#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02 +#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 +#define WPS_ASSOC_STATE_IP_FAILURE 0x04 + +/* =====================P2P Section===================== */ +/* For P2P */ +#define P2POUI 0x506F9A09 + +/* P2P Attribute ID */ +#define P2P_ATTR_STATUS 0x00 +#define P2P_ATTR_MINOR_REASON_CODE 0x01 +#define P2P_ATTR_CAPABILITY 0x02 +#define P2P_ATTR_DEVICE_ID 0x03 +#define P2P_ATTR_GO_INTENT 0x04 +#define P2P_ATTR_CONF_TIMEOUT 0x05 +#define P2P_ATTR_LISTEN_CH 0x06 +#define P2P_ATTR_GROUP_BSSID 0x07 +#define P2P_ATTR_EX_LISTEN_TIMING 0x08 +#define P2P_ATTR_INTENTED_IF_ADDR 0x09 +#define P2P_ATTR_MANAGEABILITY 0x0A +#define P2P_ATTR_CH_LIST 0x0B +#define P2P_ATTR_NOA 0x0C +#define P2P_ATTR_DEVICE_INFO 0x0D +#define P2P_ATTR_GROUP_INFO 0x0E +#define P2P_ATTR_GROUP_ID 0x0F +#define P2P_ATTR_INTERFACE 0x10 +#define P2P_ATTR_OPERATING_CH 0x11 +#define P2P_ATTR_INVITATION_FLAGS 0x12 + +/* Value of Status Attribute */ +#define P2P_STATUS_SUCCESS 0x00 +#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02 +#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03 +#define P2P_STATUS_FAIL_INVALID_PARAM 0x04 +#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05 +#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06 +#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07 +#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08 +#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A +#define P2P_STATUS_FAIL_USER_REJECT 0x0B + +/* Value of Inviation Flags Attribute */ +#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0) + +#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \ + P2P_DEVCAP_CLIENT_DISCOVERABILITY | \ + P2P_DEVCAP_CONCURRENT_OPERATION | \ + P2P_DEVCAP_INVITATION_PROC) + +#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS) + +/* Value of Device Capability Bitmap */ +#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0) +#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1) +#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2) +#define P2P_DEVCAP_INFRA_MANAGED BIT(3) +#define P2P_DEVCAP_DEVICE_LIMIT BIT(4) +#define P2P_DEVCAP_INVITATION_PROC BIT(5) + +/* Value of Group Capability Bitmap */ +#define P2P_GRPCAP_GO BIT(0) +#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1) +#define P2P_GRPCAP_GROUP_LIMIT BIT(2) +#define P2P_GRPCAP_INTRABSS BIT(3) +#define P2P_GRPCAP_CROSS_CONN BIT(4) +#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5) +#define P2P_GRPCAP_GROUP_FORMATION BIT(6) + +/* P2P Public Action Frame ( Management Frame ) */ +#define P2P_PUB_ACTION_ACTION 0x09 + +/* P2P Public Action Frame Type */ +#define P2P_GO_NEGO_REQ 0 +#define P2P_GO_NEGO_RESP 1 +#define P2P_GO_NEGO_CONF 2 +#define P2P_INVIT_REQ 3 +#define P2P_INVIT_RESP 4 +#define P2P_DEVDISC_REQ 5 +#define P2P_DEVDISC_RESP 6 +#define P2P_PROVISION_DISC_REQ 7 +#define P2P_PROVISION_DISC_RESP 8 + +/* P2P Action Frame Type */ +#define P2P_NOTICE_OF_ABSENCE 0 +#define P2P_PRESENCE_REQUEST 1 +#define P2P_PRESENCE_RESPONSE 2 +#define P2P_GO_DISC_REQUEST 3 + + +#define P2P_MAX_PERSISTENT_GROUP_NUM 10 + +#define P2P_PROVISIONING_SCAN_CNT 3 + +#define P2P_WILDCARD_SSID_LEN 7 + +#define P2P_FINDPHASE_EX_NONE 0 /* default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase */ +#define P2P_FINDPHASE_EX_FULL 1 /* used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase */ +#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) +#define P2P_FINDPHASE_EX_MAX 4 +#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX + +#define P2P_PROVISION_TIMEOUT 5000 /*5 sec timeout for sending the provision discovery request */ +#define P2P_CONCURRENT_PROVISION_TIMEOUT 3000 /*3 sec timeout for sending the provision discovery request under concurrent mode */ +#define P2P_GO_NEGO_TIMEOUT 5000 /*5 sec timeout for receiving the group negotation response */ +#define P2P_CONCURRENT_GO_NEGO_TIMEOUT 3000 /*3 sec timeout for sending the negotiation request under concurrent mode */ +#define P2P_TX_PRESCAN_TIMEOUT 100 /*100ms */ +#define P2P_INVITE_TIMEOUT 5000 /*5 sec timeout for sending the invitation request */ +#define P2P_CONCURRENT_INVITE_TIMEOUT 3000 /*3 sec timeout for sending the invitation request under concurrent mode */ +#define P2P_RESET_SCAN_CH 25000 /*25 sec t/o to reset the scan channel ( based on channel plan ) */ +#define P2P_MAX_INTENT 15 + +#define P2P_MAX_NOA_NUM 2 + +/* WPS Configuration Method */ +#define WPS_CM_NONE 0x0000 +#define WPS_CM_LABEL 0x0004 +#define WPS_CM_DISPLYA 0x0008 +#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010 +#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020 +#define WPS_CM_NFC_INTERFACE 0x0040 +#define WPS_CM_PUSH_BUTTON 0x0080 +#define WPS_CM_KEYPAD 0x0100 +#define WPS_CM_SW_PUHS_BUTTON 0x0280 +#define WPS_CM_HW_PUHS_BUTTON 0x0480 +#define WPS_CM_SW_DISPLAY_PIN 0x2008 +#define WPS_CM_LCD_DISPLAY_PIN 0x4008 + +enum P2P_ROLE { + P2P_ROLE_DISABLE = 0, + P2P_ROLE_DEVICE = 1, + P2P_ROLE_CLIENT = 2, + P2P_ROLE_GO = 3 +}; + +enum P2P_STATE { + P2P_STATE_NONE = 0, /*P2P disable */ + P2P_STATE_IDLE = 1, /*P2P had enabled and do nothing */ + P2P_STATE_LISTEN = 2, /*In pure listen state */ + P2P_STATE_SCAN = 3, /*In scan phase */ + P2P_STATE_FIND_PHASE_LISTEN = 4, /*In the listen state of find phase */ + P2P_STATE_FIND_PHASE_SEARCH = 5, /*In the search state of find phase */ + P2P_STATE_TX_PROVISION_DIS_REQ = 6, /*In P2P provisioning discovery */ + P2P_STATE_RX_PROVISION_DIS_RSP = 7, + P2P_STATE_RX_PROVISION_DIS_REQ = 8, + P2P_STATE_GONEGO_ING = 9, /*Doing the group owner negoitation handshake */ + P2P_STATE_GONEGO_OK = 10, /*finish the group negoitation handshake with success */ + P2P_STATE_GONEGO_FAIL = 11, /*finish the group negoitation handshake with failure */ + P2P_STATE_RECV_INVITE_REQ_MATCH = 12, /*receiving the P2P Inviation request and match with the profile. */ + P2P_STATE_PROVISIONING_ING = 13, /*Doing the P2P WPS */ + P2P_STATE_PROVISIONING_DONE = 14, /*Finish the P2P WPS */ + P2P_STATE_TX_INVITE_REQ = 15, /*Transmit the P2P Invitation request */ + P2P_STATE_RX_INVITE_RESP_OK = 16, /*Receiving the P2P Invitation response */ + P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,/*receiving the P2P Inviation request and dismatch with the profile. */ + P2P_STATE_RECV_INVITE_REQ_GO = 18, /*receiving the P2P Inviation request and this wifi is GO. */ + P2P_STATE_RECV_INVITE_REQ_JOIN = 19, /*receiving the P2P Inviation request to join an existing P2P Group. */ + P2P_STATE_RX_INVITE_RESP_FAIL = 20, /*receiving the P2P Inviation response with failure */ + P2P_STATE_RX_INFOR_NOREADY = 21, /*receiving p2p negotiation response with information is not available */ + P2P_STATE_TX_INFOR_NOREADY = 22, /*sending p2p negotiation response with information is not available */ +}; + +enum P2P_WPSINFO { + P2P_NO_WPSINFO = 0, + P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1, + P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2, + P2P_GOT_WPSINFO_PBC = 3, +}; + +#define P2P_PRIVATE_IOCTL_SET_LEN 64 + +enum P2P_PROTO_WK_ID { + P2P_FIND_PHASE_WK = 0, + P2P_RESTORE_STATE_WK = 1, + P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, + P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, + P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, + P2P_AP_P2P_CH_SWITCH_PROCESS_WK = 5, + P2P_RO_CH_WK = 6, +}; + +#ifdef CONFIG_8723AU_P2P +enum P2P_PS_STATE { + P2P_PS_DISABLE = 0, + P2P_PS_ENABLE = 1, + P2P_PS_SCAN = 2, + P2P_PS_SCAN_DONE = 3, + P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */ +}; + +enum P2P_PS_MODE { + P2P_PS_NONE = 0, + P2P_PS_CTWINDOW = 1, + P2P_PS_NOA = 2, + P2P_PS_MIX = 3, /* CTWindow and NoA */ +}; +#endif /* CONFIG_8723AU_P2P */ + +/* =====================WFD Section===================== */ +/* For Wi-Fi Display */ +#define WFD_ATTR_DEVICE_INFO 0x00 +#define WFD_ATTR_ASSOC_BSSID 0x01 +#define WFD_ATTR_COUPLED_SINK_INFO 0x06 +#define WFD_ATTR_LOCAL_IP_ADDR 0x08 +#define WFD_ATTR_SESSION_INFO 0x09 +#define WFD_ATTR_ALTER_MAC 0x0a + +/* For WFD Device Information Attribute */ +#define WFD_DEVINFO_SOURCE 0x0000 +#define WFD_DEVINFO_PSINK 0x0001 +#define WFD_DEVINFO_SSINK 0x0002 +#define WFD_DEVINFO_DUAL 0x0003 + +#define WFD_DEVINFO_SESSION_AVAIL 0x0010 +#define WFD_DEVINFO_WSD 0x0040 +#define WFD_DEVINFO_PC_TDLS 0x0080 +#define WFD_DEVINFO_HDCP_SUPPORT 0x0100 + +#endif /* _WIFI_H_ */ diff --git a/drivers/staging/rtl8723au/include/wlan_bssdef.h b/drivers/staging/rtl8723au/include/wlan_bssdef.h new file mode 100644 index 000000000000..92287ebe5b9b --- /dev/null +++ b/drivers/staging/rtl8723au/include/wlan_bssdef.h @@ -0,0 +1,215 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __WLAN_BSSDEF_H__ +#define __WLAN_BSSDEF_H__ + + +#define MAX_IE_SZ 768 + + +#define NDIS_802_11_LENGTH_RATES 8 +#define NDIS_802_11_LENGTH_RATES_EX 16 + +enum ndis_802_11_net_type { + Ndis802_11FH, + Ndis802_11DS, + Ndis802_11OFDM5, + Ndis802_11OFDM24, + Ndis802_11NetworkTypeMax /* just an upper bound */ +}; + +struct ndis_802_11_configuration_fh { + u32 Length; /* Length of structure */ + u32 HopPattern; /* As defined by 802.11, MSB set */ + u32 HopSet; /* to one if non-802.11 */ + u32 DwellTime; /* units are Kusec */ +}; + + +/* + FW will only save the channel number in DSConfig. + ODI Handler will convert the channel number to freq. number. +*/ +struct ndis_802_11_config { + u32 Length; /* Length of structure */ + u32 BeaconPeriod; /* units are Kusec */ + u32 ATIMWindow; /* units are Kusec */ + u32 DSConfig; /* Frequency, units are kHz */ + struct ndis_802_11_configuration_fh FHConfig; +}; + +enum ndis_802_11_net_infra { + Ndis802_11IBSS, + Ndis802_11Infrastructure, + Ndis802_11AutoUnknown, + Ndis802_11InfrastructureMax, /* Not a real value, defined as upper bound */ + Ndis802_11APMode +}; + +struct ndis_802_11_fixed_ies { + u8 Timestamp[8]; + u16 BeaconInterval; + u16 Capabilities; +}; + +struct ndis_802_11_var_ies { + u8 ElementID; + u8 Length; + u8 data[1]; +}; + +/* Length is the 4 bytes multiples of the sum of + * sizeof(6 * sizeof(unsigned char)) + 2 + sizeof(struct ndis_802_11_ssid) + + * sizeof(u32) + sizeof(long) + sizeof(enum ndis_802_11_net_type) + + * sizeof(struct ndis_802_11_config) + sizeof(sizeof(unsigned char) * + * NDIS_802_11_LENGTH_RATES_EX) + IELength + * + * Except the IELength, all other fields are fixed length. Therefore, + * we can define a macro to present the partial sum. + */ + +enum ndis_802_11_auth_mode { + Ndis802_11AuthModeOpen, + Ndis802_11AuthModeShared, + Ndis802_11AuthModeAutoSwitch, + Ndis802_11AuthModeWPA, + Ndis802_11AuthModeWPAPSK, + Ndis802_11AuthModeWPANone, + dis802_11AuthModeMax /* upper bound */ +}; + +enum { + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11Encryption2Enabled, + Ndis802_11Encryption2KeyAbsent, + Ndis802_11Encryption3Enabled, + Ndis802_11Encryption3KeyAbsent, +}; + +/* Key mapping keys require a BSSID */ +struct ndis_802_11_key { + u32 Length; /* Length of this structure */ + u32 KeyIndex; + u32 KeyLength; /* length of key in bytes */ + unsigned char BSSID[6]; + unsigned long long KeyRSC; + u8 KeyMaterial[32]; /* variable length depending on above field */ +}; + +struct ndis_802_11_wep { + u32 Length; /* Length of this structure */ + u32 KeyIndex; /* 0 is the per-client key, 1-N are global */ + u32 KeyLength; /* length of key in bytes */ + u8 KeyMaterial[16];/* variable length depending on above field */ +}; + +enum NDIS_802_11_STATUS_TYPE { + Ndis802_11StatusType_Authentication, + Ndis802_11StatusType_MediaStreamMode, + Ndis802_11StatusType_PMKID_CandidateList, + Ndis802_11StatusTypeMax /* not a real type, just an upper bound */ +}; + +/* mask for authentication/integrity fields */ +#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f +#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 +#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 +#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E + +/* MIC check time, 60 seconds. */ +#define MIC_CHECK_TIME 60000000 + +#ifndef Ndis802_11APMode +#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) +#endif + +struct wlan_phy_info { + u8 SignalStrength;/* in percentage) */ + u8 SignalQuality;/* in percentage) */ + u8 Optimum_antenna; /* for Antenna diversity */ + u8 Reserved_0; +}; + +struct wlan_bcn_info { + /* these infor get from rtw_get_encrypt_info when + * * translate scan to UI */ + u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2 */ + int group_cipher; /* WPA/WPA2 group cipher */ + int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */ + int is_8021x; + + /* bwmode 20/40 and ch_offset UP/LOW */ + unsigned short ht_cap_info; + unsigned char ht_info_infos_0; +}; + +struct wlan_bssid_ex { + u32 Length; + u8 MacAddress[ETH_ALEN]; + u16 reserved; + struct cfg80211_ssid Ssid; + u32 Privacy; + long Rssi;/* in dBM, raw data , get from PHY) */ + enum ndis_802_11_net_type NetworkTypeInUse; + struct ndis_802_11_config Configuration; + enum ndis_802_11_net_infra InfrastructureMode; + unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; + struct wlan_phy_info PhyInfo; + u32 IELength; + u8 IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and capability info*/ +} __packed; + +static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) +{ + return sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength; +} + +struct wlan_network { + struct list_head list; + int network_type; /* refer to ieee80211.h for 11A/B/G */ + /* set to fixed when not to be removed as site-surveying */ + int fixed; + unsigned long last_scanned; /* timestamp for the network */ + int aid; /* will only be valid when a BSS is joined. */ + int join_res; + struct wlan_bssid_ex network; /* must be the last item */ + struct wlan_bcn_info BcnInfo; +}; + +enum VRTL_CARRIER_SENSE { + DISABLE_VCS, + ENABLE_VCS, + AUTO_VCS +}; + +enum VCS_TYPE { + NONE_VCS, + RTS_CTS, + CTS_TO_SELF +}; + +/* john */ +#define NUM_PRE_AUTH_KEY 16 +#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY + +#endif /* ifndef WLAN_BSSDEF_H_ */ diff --git a/drivers/staging/rtl8723au/include/xmit_osdep.h b/drivers/staging/rtl8723au/include/xmit_osdep.h new file mode 100644 index 000000000000..0eca53ece75d --- /dev/null +++ b/drivers/staging/rtl8723au/include/xmit_osdep.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * 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. + * + ******************************************************************************/ +#ifndef __XMIT_OSDEP_H_ +#define __XMIT_OSDEP_H_ + +#include +#include + +struct pkt_file { + struct sk_buff *pkt; + __kernel_size_t pkt_len; /* the remainder length of the open_file */ + unsigned char *cur_buffer; + u8 *buf_start; + u8 *cur_addr; + __kernel_size_t buf_len; +}; + + +#define NR_XMITFRAME 256 + +struct xmit_priv; +struct pkt_attrib; +struct sta_xmit_priv; +struct xmit_frame; +struct xmit_buf; + +int rtw_xmit23a_entry23a(struct sk_buff *pkt, struct net_device *pnetdev); + +void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter); + +int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter, + struct xmit_buf *pxmitbuf, u32 alloc_sz); +void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter, + struct xmit_buf *pxmitbuf); +uint rtw_remainder_len23a(struct pkt_file *pfile); +void _rtw_open_pktfile23a(struct sk_buff *pkt, struct pkt_file *pfile); +uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen); +int rtw_endofpktfile23a(struct pkt_file *pfile); + +void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt); +void rtw_os_xmit_complete23a(struct rtw_adapter *padapter, + struct xmit_frame *pxframe); +int netdev_open23a(struct net_device *pnetdev); + +#endif /* __XMIT_OSDEP_H_ */ -- cgit v1.2.3 From c17416ef707312429aafcdc4597db73906f3572e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:42 -0500 Subject: staging: r8723au: Additional source patches These changes are fixes that were discovered late in the testing cycle. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/core/rtw_ap.c | 4 +- drivers/staging/rtl8723au/core/rtw_cmd.c | 8 +- drivers/staging/rtl8723au/core/rtw_efuse.c | 2 - drivers/staging/rtl8723au/core/rtw_ieee80211.c | 24 +- drivers/staging/rtl8723au/core/rtw_mlme.c | 13 +- drivers/staging/rtl8723au/core/rtw_mlme_ext.c | 38 +-- drivers/staging/rtl8723au/core/rtw_p2p.c | 280 ++++++++++++--------- drivers/staging/rtl8723au/core/rtw_pwrctrl.c | 39 +-- drivers/staging/rtl8723au/core/rtw_security.c | 11 +- drivers/staging/rtl8723au/core/rtw_sreset.c | 2 + drivers/staging/rtl8723au/core/rtw_wlan_util.c | 2 +- drivers/staging/rtl8723au/core/rtw_xmit.c | 7 +- drivers/staging/rtl8723au/hal/hal_intf.c | 2 + .../staging/rtl8723au/hal/rtl8723a_bt-coexist.c | 10 +- drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c | 2 +- drivers/staging/rtl8723au/hal/rtl8723au_xmit.c | 2 +- drivers/staging/rtl8723au/include/Hal8723APhyCfg.h | 2 - drivers/staging/rtl8723au/include/drv_types.h | 4 - drivers/staging/rtl8723au/include/odm.h | 17 +- drivers/staging/rtl8723au/include/odm_HWConfig.h | 16 +- drivers/staging/rtl8723au/include/osdep_service.h | 133 ---------- .../rtl8723au/include/rtl8723a_bt-coexist.h | 4 +- drivers/staging/rtl8723au/include/rtl8723a_pg.h | 23 +- drivers/staging/rtl8723au/include/rtw_mlme.h | 52 ++-- drivers/staging/rtl8723au/include/rtw_mlme_ext.h | 2 - drivers/staging/rtl8723au/include/rtw_pwrctrl.h | 2 +- drivers/staging/rtl8723au/include/rtw_recv.h | 11 +- drivers/staging/rtl8723au/include/sta_info.h | 15 +- drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | 55 +++- drivers/staging/rtl8723au/os_dep/osdep_service.c | 254 ------------------- drivers/staging/rtl8723au/os_dep/usb_intf.c | 7 +- 31 files changed, 343 insertions(+), 700 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c index 3d936eb937ef..a357e98cb83e 100644 --- a/drivers/staging/rtl8723au/core/rtw_ap.c +++ b/drivers/staging/rtl8723au/core/rtw_ap.c @@ -842,10 +842,10 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf, int len) /* beacon interval */ /* ie + 8; 8: TimeStamp, 2: Beacon Interval 2:Capability */ p = rtw_get_beacon_interval23a_from_ie(ie); - pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p); + pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(p); /* capability */ - cap = RTW_GET_LE16(ie); + cap = get_unaligned_le16(ie); /* SSID */ p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c index dbc6401c6e13..5e3088a01800 100644 --- a/drivers/staging/rtl8723au/core/rtw_cmd.c +++ b/drivers/staging/rtl8723au/core/rtw_cmd.c @@ -447,7 +447,7 @@ _next: pcmdpriv->cmd_issued_cnt++; - pcmd->cmdsz = _RND4(pcmd->cmdsz);/* _RND4 */ + pcmd->cmdsz = ALIGN(pcmd->cmdsz, 4); memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); @@ -1141,7 +1141,9 @@ static void traffic_status_watchdog(struct rtw_adapter *padapter) u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false; u8 bHigherBusyTxTraffic = false; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - +#ifndef CONFIG_8723AU_BT_COEXIST + int BusyThreshold = 100; +#endif /* */ /* Determine if our traffic is busy now */ /* */ @@ -1638,12 +1640,12 @@ u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf) case P2P_PS_WK_CID: p2p_ps_wk_hdl23a(padapter, pdrvextra_cmd->type_size); break; -#endif /* CONFIG_8723AU_P2P */ case P2P_PROTO_WK_CID: /* Commented by Albert 2011/07/01 */ /* I used the type_size as the type command */ p2p_protocol_wk_hdl23a(padapter, pdrvextra_cmd->type_size); break; +#endif /* CONFIG_8723AU_P2P */ #ifdef CONFIG_8723AU_AP_MODE case CHECK_HIQ_WK_CID: rtw_chk_hi_queue_hdl(padapter); diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c index 94221ee45bd2..35b177fd0510 100644 --- a/drivers/staging/rtl8723au/core/rtw_efuse.c +++ b/drivers/staging/rtl8723au/core/rtw_efuse.c @@ -108,7 +108,6 @@ ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf) u32 value32; u8 readbyte; u16 retry; - /* u32 start = rtw_get_current_time(); */ /* Write Address */ rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff)); @@ -137,7 +136,6 @@ ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf) value32 = rtw_read32(Adapter, EFUSE_CTRL); *pbuf = (u8)(value32 & 0xff); - /* DBG_8723A("ReadEFuseByte23a _offset:%08u, in %d ms\n", _offset , rtw_get_passing_time_ms23a(start)); */ } /* */ diff --git a/drivers/staging/rtl8723au/core/rtw_ieee80211.c b/drivers/staging/rtl8723au/core/rtw_ieee80211.c index 8287f447cbdd..780631fd3b6d 100644 --- a/drivers/staging/rtl8723au/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723au/core/rtw_ieee80211.c @@ -196,8 +196,8 @@ inline u8 *rtw_set_ie23a_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, ie_data[0] = ttl; ie_data[1] = flags; - RTW_PUT_LE16((u8*)&ie_data[2], reason); - RTW_PUT_LE16((u8*)&ie_data[4], precedence); + put_unaligned_le16(reason, (u8*)&ie_data[2]); + put_unaligned_le16(precedence, (u8*)&ie_data[4]); return rtw_set_ie23a(buf, 0x118, 6, ie_data, buf_len); } @@ -585,7 +585,7 @@ int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pair /* pairwise_cipher */ if (left >= 2) { /* count = le16_to_cpu(*(u16*)pos); */ - count = RTW_GET_LE16(pos); + count = get_unaligned_le16(pos); pos += 2; left -= 2; @@ -661,7 +661,7 @@ int rtw_parse_wpa2_ie23a(u8* rsn_ie, int rsn_ie_len, int *group_cipher, /* pairwise_cipher */ if (left >= 2) { /* count = le16_to_cpu(*(u16*)pos); */ - count = RTW_GET_LE16(pos); + count = get_unaligned_le16(pos); pos += 2; left -= 2; @@ -876,8 +876,8 @@ u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, while (attr_ptr - wps_ie < wps_ielen) { /* 4 = 2(Attribute ID) + 2(Length) */ - u16 attr_id = RTW_GET_BE16(attr_ptr); - u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2); + u16 attr_id = get_unaligned_be16(attr_ptr); + u16 attr_data_len = get_unaligned_be16(attr_ptr + 2); u16 attr_len = attr_data_len + 4; /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ @@ -1246,8 +1246,8 @@ void dump_wps_ie23a(u8 *ie, u32 ie_len) { pos+= 6; while (pos-ie < ie_len) { - id = RTW_GET_BE16(pos); - len = RTW_GET_BE16(pos + 2); + id = get_unaligned_be16(pos); + len = get_unaligned_be16(pos + 2); DBG_8723A("%s ID:0x%04x, LEN:%u\n", __func__, id, len); @@ -1271,7 +1271,7 @@ void dump_p2p_ie23a(u8 *ie, u32 ie_len) { pos += 6; while (pos-ie < ie_len) { id = *pos; - len = RTW_GET_LE16(pos+1); + len = get_unaligned_le16(pos+1); DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len); @@ -1362,7 +1362,7 @@ u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, while (attr_ptr - p2p_ie < p2p_ielen) { /* 3 = 1(Attribute ID) + 2(Length) */ u8 attr_id = *attr_ptr; - u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1); + u16 attr_data_len = get_unaligned_le16(attr_ptr + 1); u16 attr_len = attr_data_len + 3; /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */ @@ -1429,7 +1429,7 @@ u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_at *pbuf = attr_id; /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ - RTW_PUT_LE16(pbuf + 1, attr_len); + put_unaligned_le16(attr_len, pbuf + 1); if (pdata_attr) memcpy(pbuf + 3, pdata_attr, attr_len); @@ -1561,7 +1561,7 @@ int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, /* 1 (WFD IE) + 1 (Length) + 3 (OUI) + 1 (OUI Type) */ cnt = 6; while (cnt < wfd_ielen) { - u16 attrlen = RTW_GET_BE16(wfd_ie + cnt + 1); + u16 attrlen = get_unaligned_be16(wfd_ie + cnt + 1); attr_id = wfd_ie[cnt]; if (attr_id == target_attr_id) { diff --git a/drivers/staging/rtl8723au/core/rtw_mlme.c b/drivers/staging/rtl8723au/core/rtw_mlme.c index 71749a37a78e..6cee78785bdc 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme.c @@ -69,6 +69,7 @@ int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter) return res; } +#ifdef CONFIG_8723AU_AP_MODE static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) { if(*ppie) @@ -78,6 +79,7 @@ static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) *ppie=NULL; } } +#endif void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) { @@ -94,9 +96,7 @@ void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); -#endif -#if defined(CONFIG_8723AU_P2P) rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); @@ -941,7 +941,7 @@ void rtw_indicate_disconnect23a(struct rtw_adapter *padapter) /* set ips_deny_time to avoid enter IPS before LPS leave */ padapter->pwrctrlpriv.ips_deny_time = - rtw_get_current_time() + rtw_ms_to_systime23a(3000); + jiffies + msecs_to_jiffies(3000); _clr_fwstate_(pmlmepriv, _FW_LINKED); @@ -1675,7 +1675,7 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv } /* check ssid, if needed */ - if (pmlmepriv->assoc_ssid.ssid && pmlmepriv->assoc_ssid.ssid_len) { + if (pmlmepriv->assoc_ssid.ssid_len) { if (competitor->network.Ssid.ssid_len != pmlmepriv->assoc_ssid.ssid_len || memcmp(competitor->network.Ssid.ssid, @@ -1839,8 +1839,7 @@ int rtw_set_key23a(struct rtw_adapter *adapter, res = _FAIL; /* try again */ goto exit; } - psetkeyparm = (struct setkey_parm *) - kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); + psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); if (!psetkeyparm) { kfree(pcmd); res = _FAIL; @@ -1902,6 +1901,8 @@ int rtw_set_key23a(struct rtw_adapter *adapter, "%x (must be 1 or 2 or 4 or 5)\n", psecuritypriv->dot11PrivacyAlgrthm)); res = _FAIL; + kfree(pcmd); + kfree(psetkeyparm); goto exit; } diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c index 75ccdec881e5..4c753639ea5a 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c @@ -762,9 +762,9 @@ unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +#ifdef CONFIG_8723AU_P2P struct sk_buff *skb = precv_frame->pkt; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -#ifdef CONFIG_8723AU_P2P struct wifidirect_info *pwdinfo = &padapter->wdinfo; #endif @@ -1309,10 +1309,10 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec goto asoc_class2_error; } - capab_info = RTW_GET_LE16(pframe + sizeof(struct ieee80211_hdr_3addr)); + capab_info = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr)); /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); */ /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)+2)); */ - listen_interval = RTW_GET_LE16(pframe + sizeof(struct ieee80211_hdr_3addr)+2); + listen_interval = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr)+2); left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); @@ -1665,7 +1665,7 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); if (attr_contentlen) { - pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); } } @@ -2091,7 +2091,7 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame } break; case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ - status = RTW_GET_LE16(&frame_body[3]); + status = get_unaligned_le16(&frame_body[3]); tid = ((frame_body[5] >> 2) & 0x7); if (status == 0) { /* successful */ DBG_8723A("agg_enable for TID =%d\n", tid); @@ -2110,7 +2110,7 @@ unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame ~(1 << ((frame_body[3] >> 4) & 0xf)); /* reason_code = frame_body[4] | (frame_body[5] << 8); */ - reason_code = RTW_GET_LE16(&frame_body[4]); + reason_code = get_unaligned_le16(&frame_body[4]); } else if ((frame_body[3] & BIT(3)) == BIT(3)) { tid = (frame_body[3] >> 4) & 0x0F; @@ -4531,14 +4531,14 @@ static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) static unsigned int on_action_public23a_p2p(struct recv_frame *precv_frame) { - struct rtw_adapter *padapter = precv_frame->adapter; struct sk_buff *skb = precv_frame->pkt; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u8 *pframe = skb->data; - uint len = skb->len; u8 *frame_body; u8 dialogToken = 0; #ifdef CONFIG_8723AU_P2P + struct rtw_adapter *padapter = precv_frame->adapter; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + uint len = skb->len; u8 *p2p_ie; u32 p2p_ielen; struct wifidirect_info *pwdinfo = &padapter->wdinfo; @@ -5262,9 +5262,7 @@ void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms) unsigned short *fctrl; unsigned int rate_len; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -#ifdef CONFIG_8723AU_AP_MODE struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -#endif struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; @@ -5579,6 +5577,13 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, #ifdef CONFIG_8723AU_AP_MODE u8 *pwps_ie; uint wps_ielen; + u8 *ssid_ie; + int ssid_ielen; + int ssid_ielen_diff; + u8 buf[MAX_IE_SZ]; + u8 *ies; +#endif +#if defined(CONFIG_8723AU_AP_MODE) || defined(CONFIG_8723AU_P2P) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; #endif struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; @@ -5588,11 +5593,6 @@ void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da, #ifdef CONFIG_8723AU_P2P struct wifidirect_info *pwdinfo = &padapter->wdinfo; #endif /* CONFIG_8723AU_P2P */ - u8 *ssid_ie; - int ssid_ielen; - int ssid_ielen_diff; - u8 buf[MAX_IE_SZ]; - u8 *ies; /* DBG_8723A("%s\n", __func__); */ @@ -7559,6 +7559,7 @@ unsigned int send_beacon23a(struct rtw_adapter *padapter) int issue = 0; int poll = 0; unsigned long start = jiffies; + unsigned int passing_time; rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_VALID, NULL); do { @@ -7578,11 +7579,12 @@ unsigned int send_beacon23a(struct rtw_adapter *padapter) if (padapter->bSurpriseRemoved || padapter->bDriverStopped) return _FAIL; + passing_time = jiffies_to_msecs(jiffies - start); + if (!bxmitok) { - DBG_8723A("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms23a(start)); + DBG_8723A("%s fail! %u ms\n", __func__, passing_time); return _FAIL; } else { - unsigned int passing_time = jiffies_to_msecs(jiffies - start); if (passing_time > 100 || issue > 3) DBG_8723A("%s success, issue:%d, poll:%d, %u ms\n", diff --git a/drivers/staging/rtl8723au/core/rtw_p2p.c b/drivers/staging/rtl8723au/core/rtw_p2p.c index becc3feaca1d..27a6cc76973d 100644 --- a/drivers/staging/rtl8723au/core/rtw_p2p.c +++ b/drivers/staging/rtl8723au/core/rtw_p2p.c @@ -81,7 +81,7 @@ static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) pcur++; /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */ - RTW_PUT_BE16(pcur, psta->config_methods); + put_unaligned_be16(psta->config_methods, pcur); pcur += 2; memcpy(pcur, psta->primary_dev_type, 8); @@ -96,11 +96,11 @@ static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) if (psta->dev_name_len>0) { /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); + put_unaligned_be16(WPS_ATTR_DEVICE_NAME, pcur); pcur += 2; /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */ - RTW_PUT_BE16(pcur, psta->dev_name_len); + put_unaligned_be16(psta->dev_name_len, pcur); pcur += 2; memcpy(pcur, psta->dev_name, psta->dev_name_len); @@ -320,23 +320,23 @@ static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8* raddr, wpsielen = 0; /* WPS OUI */ /* u32*) (wpsie) = cpu_to_be32(WPSOUI); */ - RTW_PUT_BE32(wpsie, WPSOUI); + put_unaligned_be32(WPSOUI, wpsie); wpsielen += 4; /* Config Method */ /* Type: */ /* u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); */ - RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); + put_unaligned_be16(WPS_ATTR_CONF_METHOD, wpsie + wpsielen); wpsielen += 2; /* Length: */ /* u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); */ - RTW_PUT_BE16(wpsie + wpsielen, 0x0002); + put_unaligned_be16(0x0002, wpsie + wpsielen); wpsielen += 2; /* Value: */ /* u16*) (wpsie + wpsielen) = cpu_to_be16(config_method); */ - RTW_PUT_BE16(wpsie + wpsielen, config_method); + put_unaligned_be16(config_method, wpsie + wpsielen); wpsielen += 2; pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); @@ -513,7 +513,7 @@ u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ @@ -524,19 +524,24 @@ u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) if (is_any_client_associated(pwdinfo->padapter)) { /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_WSD, wfdie + wfdielen); } else { /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD, wfdie + wfdielen); } } else { /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD, wfdie + wfdielen); } wfdielen += 2; @@ -544,13 +549,13 @@ u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -559,7 +564,7 @@ u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -581,7 +586,7 @@ u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -628,7 +633,7 @@ u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ @@ -637,17 +642,17 @@ u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) if (1 == pwdinfo->wfd_tdls_enable) { /* WFD primary sink + available for WFD session + WiFi TDLS mode + WSC (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD | - WFD_DEVINFO_PC_TDLS); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD | + WFD_DEVINFO_PC_TDLS, wfdie + wfdielen); } else { /* WFD primary sink + available for WFD session + WiFi Direct mode + WSC (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | - WFD_DEVINFO_SESSION_AVAIL | - WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD, wfdie + wfdielen); } wfdielen += 2; @@ -655,13 +660,13 @@ u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -670,7 +675,7 @@ u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -692,7 +697,7 @@ u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -740,7 +745,7 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ @@ -756,12 +761,12 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel if (pwdinfo->wfd_tdls_enable) { /* TDLS mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); } else { /* WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); } } else @@ -769,12 +774,12 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel if (pwdinfo->wfd_tdls_enable) { /* available for WFD session + TDLS mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); } else { /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen); } } } @@ -783,13 +788,22 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel if (pwdinfo->wfd_tdls_enable) { /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD | + WFD_DEVINFO_PC_TDLS | + WFD_DEVINFO_HDCP_SUPPORT, + wfdie + wfdielen); } else { /* available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD | + WFD_DEVINFO_HDCP_SUPPORT, + wfdie + wfdielen); } } } @@ -797,11 +811,18 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel { if (pwdinfo->wfd_tdls_enable) { - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD |WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_WSD | + WFD_DEVINFO_PC_TDLS | + WFD_DEVINFO_HDCP_SUPPORT, + wfdie + wfdielen); } else { - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_WSD | + WFD_DEVINFO_HDCP_SUPPORT, + wfdie + wfdielen); } } @@ -811,13 +832,13 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -826,7 +847,7 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -848,7 +869,7 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -871,7 +892,7 @@ u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunnel /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + put_unaligned_be16(0x0000, wfdie + wfdielen); wfdielen += 2; /* Todo: to add the list of WFD device info descriptor in WFD group. */ @@ -919,25 +940,27 @@ u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD, wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -946,7 +969,7 @@ u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -968,7 +991,7 @@ u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1015,25 +1038,27 @@ u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD, wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1042,7 +1067,7 @@ u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1064,7 +1089,7 @@ u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1111,25 +1136,27 @@ u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1138,7 +1165,7 @@ u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1160,7 +1187,7 @@ u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1207,25 +1234,27 @@ u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1234,7 +1263,7 @@ u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1256,7 +1285,7 @@ u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1303,25 +1332,26 @@ u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL); + put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | + WFD_DEVINFO_SESSION_AVAIL, wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1330,7 +1360,7 @@ u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1352,7 +1382,7 @@ u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1399,25 +1429,27 @@ u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1426,7 +1458,7 @@ u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1448,7 +1480,7 @@ u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1471,7 +1503,7 @@ u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + put_unaligned_be16(0x0000, wfdie + wfdielen); wfdielen += 2; /* Todo: to add the list of WFD device info descriptor in WFD group. */ @@ -1510,25 +1542,27 @@ u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1537,7 +1571,7 @@ u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1559,7 +1593,7 @@ u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1582,7 +1616,7 @@ u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + put_unaligned_be16(0x0000, wfdie + wfdielen); wfdielen += 2; /* Todo: to add the list of WFD device info descriptor in WFD group. */ @@ -1621,25 +1655,27 @@ u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1648,7 +1684,7 @@ u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1670,7 +1706,7 @@ u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1717,25 +1753,27 @@ u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value1: */ /* WFD device information */ /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD); + put_unaligned_be16(pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD, + wfdie + wfdielen); wfdielen += 2; /* Value2: */ /* Session Management Control Port */ /* Default TCP port for RTSP messages is 554 */ - RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen); wfdielen += 2; /* Value3: */ /* WFD Device Maximum Throughput */ /* 300Mbps is the maximum throughput */ - RTW_PUT_BE16(wfdie + wfdielen, 300); + put_unaligned_be16(300, wfdie + wfdielen); wfdielen += 2; /* Associated BSSID ATTR */ @@ -1744,7 +1782,7 @@ u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + put_unaligned_be16(0x0006, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1766,7 +1804,7 @@ u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* Note: In the WFD specification, the size of length field is 2. */ - RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + put_unaligned_be16(0x0007, wfdie + wfdielen); wfdielen += 2; /* Value: */ @@ -1814,7 +1852,7 @@ u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ - RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + put_unaligned_le16(0x0002, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -1846,18 +1884,18 @@ u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */ - RTW_PUT_LE16(p2pie + p2pielen, 0x0004); + put_unaligned_le16(0x0004, p2pie + p2pielen); p2pielen += 2; /* Value: */ /* Availability Period */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ - RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + put_unaligned_le16(0xFFFF, p2pie + p2pielen); p2pielen += 2; /* Availability Interval */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ - RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + put_unaligned_le16(0xFFFF, p2pie + p2pielen); p2pielen += 2; /* Notice of Absence ATTR */ @@ -1877,7 +1915,7 @@ u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ - RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -1888,23 +1926,23 @@ u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Config Method */ /* This field should be big endian. Noted by P2P specification. */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */ - RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); + put_unaligned_be16(pwdinfo->supported_wps_cm, p2pie + p2pielen); p2pielen += 2; /* Primary Device Type */ /* Category ID */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen); p2pielen += 2; /* OUI */ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ - RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + put_unaligned_be32(WPSOUI, p2pie + p2pielen); p2pielen += 4; /* Sub Category ID */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen); p2pielen += 2; /* Number of Secondary Device Types */ @@ -1913,12 +1951,12 @@ u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf) /* Device Name */ /* Type: */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen); p2pielen += 2; /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ - RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -1963,7 +2001,7 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ - RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + put_unaligned_le16(0x0002, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -1984,7 +2022,7 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ - RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -1997,12 +2035,12 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) { /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); + put_unaligned_be16(WPS_CONFIG_METHOD_PBC, p2pie + p2pielen); } else { /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); + put_unaligned_be16(WPS_CONFIG_METHOD_DISPLAY, p2pie + p2pielen); } p2pielen += 2; @@ -2010,17 +2048,17 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, /* Primary Device Type */ /* Category ID */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen); p2pielen += 2; /* OUI */ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ - RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + put_unaligned_be32(WPSOUI, p2pie + p2pielen); p2pielen += 4; /* Sub Category ID */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen); p2pielen += 2; /* Number of Secondary Device Types */ @@ -2029,12 +2067,12 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, /* Device Name */ /* Type: */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ - RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen); p2pielen += 2; /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ - RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -2052,7 +2090,7 @@ u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, /* Length: */ /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */ - RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); + put_unaligned_le16(ETH_ALEN + ussidlen, p2pie + p2pielen); p2pielen += 2; /* Value: */ @@ -2685,7 +2723,7 @@ u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, u8 *pfra rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); if (attr_contentlen) { - pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); } } @@ -2926,7 +2964,7 @@ u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, u8 *pfr rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); if (attr_contentlen) { - pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); } } @@ -3859,7 +3897,7 @@ void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role) rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); - pwdinfo->listen_dwell = (u8) ((rtw_get_current_time() % 3) + 1); + pwdinfo->listen_dwell = (u8) ((jiffies % 3) + 1); /* DBG_8723A("[%s] listen_dwell time is %d00ms\n", __func__, pwdinfo->listen_dwell); */ memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); diff --git a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c index 354873ca344e..8ddd67f194ba 100644 --- a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c @@ -108,13 +108,11 @@ static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter) struct rtw_adapter *buddy = adapter->pbuddy_adapter; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct xmit_priv *pxmit_priv = &adapter->xmitpriv; -#ifdef CONFIG_8723AU_P2P struct wifidirect_info *pwdinfo = &adapter->wdinfo; -#endif bool ret = false; - if (adapter->pwrctrlpriv.ips_deny_time >= rtw_get_current_time()) + if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies)) goto exit; if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) @@ -129,9 +127,7 @@ static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter) /* consider buddy, if exist */ if (buddy) { struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv; -#ifdef CONFIG_8723AU_P2P struct wifidirect_info *b_pwdinfo = &buddy->wdinfo; -#endif if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) @@ -386,11 +382,13 @@ void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u */ s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms) { - u32 start_time; + unsigned long start_time, end_time; u8 bAwake = false; s32 err = 0; - start_time = rtw_get_current_time(); + start_time = jiffies; + end_time = start_time + msecs_to_jiffies(delay_ms); + while (1) { rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); @@ -404,8 +402,7 @@ s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms) break; } - if (rtw_get_passing_time_ms23a(start_time) > delay_ms) - { + if (time_after(jiffies, end_time)) { err = -1; DBG_8723A("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); break; @@ -539,7 +536,7 @@ u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms) { struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ms); + pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms); } /* @@ -554,14 +551,18 @@ int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const ch struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int ret = _SUCCESS; - u32 start = rtw_get_current_time(); + unsigned long start = jiffies; + unsigned long new_deny_time; + + new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); - if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms)) - pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms); + if (time_before(pwrpriv->ips_deny_time, new_deny_time)) + pwrpriv->ips_deny_time = new_deny_time; if (pwrpriv->ps_processing) { DBG_8723A("%s wait ps_processing...\n", __func__); - while (pwrpriv->ps_processing && rtw_get_passing_time_ms23a(start) <= 3000) + while (pwrpriv->ps_processing && + jiffies_to_msecs(jiffies - start) <= 3000) msleep(10); if (pwrpriv->ps_processing) DBG_8723A("%s wait ps_processing timeout\n", __func__); @@ -571,7 +572,8 @@ int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const ch if (rtw_hal_sreset_inprogress(padapter)) { DBG_8723A("%s wait sreset_inprogress...\n", __func__); - while (rtw_hal_sreset_inprogress(padapter) && rtw_get_passing_time_ms23a(start) <= 4000) + while (rtw_hal_sreset_inprogress(padapter) && + jiffies_to_msecs(jiffies - start) <= 4000) msleep(10); if (rtw_hal_sreset_inprogress(padapter)) DBG_8723A("%s wait sreset_inprogress timeout\n", __func__); @@ -582,7 +584,7 @@ int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const ch if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) { DBG_8723A("%s wait bInSuspend...\n", __func__); while (pwrpriv->bInSuspend && - (rtw_get_passing_time_ms23a(start) <= 3000)) { + (jiffies_to_msecs(jiffies - start) <= 3000)) { msleep(10); } if (pwrpriv->bInSuspend) @@ -630,8 +632,9 @@ int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const ch } exit: - if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms)) - pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms); + new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms); + if (time_before(pwrpriv->ips_deny_time, new_deny_time)) + pwrpriv->ips_deny_time = new_deny_time; return ret; } diff --git a/drivers/staging/rtl8723au/core/rtw_security.c b/drivers/staging/rtl8723au/core/rtw_security.c index 0d457144fde7..fd43e71bf6d6 100644 --- a/drivers/staging/rtl8723au/core/rtw_security.c +++ b/drivers/staging/rtl8723au/core/rtw_security.c @@ -202,7 +202,7 @@ void rtw_wep_encrypt23a(struct rtw_adapter *padapter, arcfour_encrypt(&mycontext, payload + length, crc, 4); pframe += pxmitpriv->frag_len; - pframe = (u8 *)RND4((unsigned long)(pframe)); + pframe = PTR_ALIGN(pframe, 4); } } @@ -225,7 +225,7 @@ void rtw_wep_decrypt23a(struct rtw_adapter *padapter, pframe = skb->data; /* start to decrypt recvframe */ - if ((prxattrib->encrypt =! _WEP40_) && (prxattrib->encrypt != _WEP104_)) + if ((prxattrib->encrypt != _WEP40_) && (prxattrib->encrypt != _WEP104_)) return; iv = pframe + prxattrib->hdrlen; @@ -699,8 +699,7 @@ u32 rtw_tkip_encrypt23a(struct rtw_adapter *padapter, arcfour_encrypt(&mycontext, payload+length, crc, 4); pframe+= pxmitpriv->frag_len; - pframe = (u8 *)RND4((unsigned long)(pframe)); - + pframe = PTR_ALIGN(pframe, 4); } } @@ -1371,7 +1370,7 @@ u32 rtw_aes_encrypt23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitfra aes_cipher(prwskey, pattrib->hdrlen, pframe, length); pframe += pxmitpriv->frag_len; - pframe = (u8*)RND4((unsigned long)pframe); + pframe = PTR_ALIGN(pframe, 4); } } out: @@ -1599,7 +1598,7 @@ u32 rtw_aes_decrypt23a(struct rtw_adapter *padapter, struct recv_frame *precvfra pframe = skb->data; /* 4 start to encrypt each fragment */ - if (!prxattrib->encrypt != _AES_) + if (prxattrib->encrypt != _AES_) return _FAIL; stainfo = rtw_get_stainfo23a(&padapter->stapriv, &prxattrib->ta[0]); diff --git a/drivers/staging/rtl8723au/core/rtw_sreset.c b/drivers/staging/rtl8723au/core/rtw_sreset.c index 8d1a6fe168ac..4f7459203390 100644 --- a/drivers/staging/rtl8723au/core/rtw_sreset.c +++ b/drivers/staging/rtl8723au/core/rtw_sreset.c @@ -165,9 +165,11 @@ static void sreset_restore_network_status(struct rtw_adapter *padapter) if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); sreset_restore_network_station(padapter); +#ifdef CONFIG_8723AU_AP_MODE } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); rtw_ap_restore_network(padapter); +#endif } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) { DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); } else { diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c index 76d2f240656e..0dfcfbce3b52 100644 --- a/drivers/staging/rtl8723au/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723au/core/rtw_wlan_util.c @@ -581,7 +581,7 @@ int WFD_info_handler(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * DBG_8723A("[%s] Found WFD IE\n", __func__); rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen); if (attr_contentlen) { - pwdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2); DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport); return true; } diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c index a1abba053944..0f10cfa10d39 100644 --- a/drivers/staging/rtl8723au/core/rtw_xmit.c +++ b/drivers/staging/rtl8723au/core/rtw_xmit.c @@ -785,7 +785,7 @@ static s32 xmitframe_addmic(struct rtw_adapter *padapter, for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { - payload = (u8 *)RND4((unsigned long)payload); + payload = PTR_ALIGN(payload, 4); RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("=== curfragnum =%d, pframe = 0x%.2x, " "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x" @@ -1124,7 +1124,6 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; - unsigned long addr; u8 *pframe, *mem_start; u8 hw_hdr_offset; u8 *pbuf_start; @@ -1261,9 +1260,7 @@ s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt, RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); } - addr = (unsigned long)pframe; - - mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; + mem_start = PTR_ALIGN(pframe, 4) + hw_hdr_offset; memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); } diff --git a/drivers/staging/rtl8723au/hal/hal_intf.c b/drivers/staging/rtl8723au/hal/hal_intf.c index c1a5b735ecf3..de3608b4010a 100644 --- a/drivers/staging/rtl8723au/hal/hal_intf.c +++ b/drivers/staging/rtl8723au/hal/hal_intf.c @@ -259,7 +259,9 @@ void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level) pmlmepriv = &padapter->mlmepriv; if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { +#ifdef CONFIG_8723AU_AP_MODE add_RATid23a(padapter, psta, rssi_level); +#endif } else { if (padapter->HalFunc.UpdateRAMaskHandler) padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level); diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c index 2d4135f741eb..9d738d79de4b 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c @@ -4620,11 +4620,11 @@ bthci_StateConnected(struct rtw_adapter *padapter, /*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */ struct bt_30info *pBTInfo = GET_BT_INFO(padapter); struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt; + u8 i; + u16 logicHandle = 0; RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Connected], ")); switch (StateCmd) { - u8 i; - u16 logicHandle = 0; case STATE_CMD_DISCONNECT_PHY_LINK: RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n")); @@ -7076,17 +7076,17 @@ static void btdm_2AntBtInquiryPage(struct rtw_adapter *padapter) static u8 btdm_HoldForBtInqPage(struct rtw_adapter *padapter) { struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); - u32 curTime = rtw_get_current_time(); + u32 curTime = jiffies; if (pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage) { /* bt inquiry or page is started. */ if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime == 0) { pHalData->bt_coexist.halCoex8723.btInqPageStartTime = curTime; - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page is started at time : 0x%"i64fmt"x \n", + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page is started at time : 0x%lx \n", pHalData->bt_coexist.halCoex8723.btInqPageStartTime)); } } - RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page started time : 0x%"i64fmt"x, curTime : 0x%x \n", + RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page started time : 0x%lx, curTime : 0x%x \n", pHalData->bt_coexist.halCoex8723.btInqPageStartTime, curTime)); if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime) { diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c index fd00ddb3c951..0982b0a4ab9b 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -388,7 +388,7 @@ s32 rtl8723a_FirmwareDownload(struct rtw_adapter *padapter) rtStatus = _WriteFW(padapter, buf, fw_size); if (rtStatus == _SUCCESS || - (rtw_get_passing_time_ms23a(fwdl_start_time) > 500 && + (jiffies_to_msecs(jiffies - fwdl_start_time) > 500 && writeFW_retry++ >= 3)) break; diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c index 3165ff5dfa73..2af2e3ee1abc 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c +++ b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c @@ -366,7 +366,7 @@ static s32 rtw_dump_xframe(struct rtw_adapter *padapter, struct xmit_frame *pxmi mem_addr += w_sz; - mem_addr = (u8 *)RND4(((unsigned long)(mem_addr))); + mem_addr = PTR_ALIGN(mem_addr, 4); } rtw_free_xmitframe23a(pxmitpriv, pxmitframe); diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h index 4aa8cdb5fb90..1478d311683a 100644 --- a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h +++ b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h @@ -65,8 +65,6 @@ enum RF_RADIO_PATH { RF_PATH_MAX /* Max RF number 90 support */ }; -#define RF_PATH_MAX 3 - #define CHANNEL_MAX_NUMBER 14 /* 14 is the max channel number */ #define CHANNEL_GROUP_MAX 3 /* ch1~3, ch4~9, ch10~14 total three groups */ diff --git a/drivers/staging/rtl8723au/include/drv_types.h b/drivers/staging/rtl8723au/include/drv_types.h index 58479884254a..53eecea48cec 100644 --- a/drivers/staging/rtl8723au/include/drv_types.h +++ b/drivers/staging/rtl8723au/include/drv_types.h @@ -258,13 +258,9 @@ struct rtw_adapter { struct hostapd_priv *phostapdpriv; #endif -#ifdef CONFIG_8723AU_P2P struct cfg80211_wifidirect_info cfg80211_wdinfo; -#endif /* CONFIG_8723AU_P2P */ u32 setband; -#ifdef CONFIG_8723AU_P2P struct wifidirect_info wdinfo; -#endif /* CONFIG_8723AU_P2P */ #ifdef CONFIG_8723AU_P2P struct wifi_display_info wfd_info; diff --git a/drivers/staging/rtl8723au/include/odm.h b/drivers/staging/rtl8723au/include/odm.h index ac4273288cca..dfedfbb48fc2 100644 --- a/drivers/staging/rtl8723au/include/odm.h +++ b/drivers/staging/rtl8723au/include/odm.h @@ -265,35 +265,30 @@ struct odm_rate_adapt { #define DM_Type_ByFW 0 #define DM_Type_ByDriver 1 -/* */ -/* Declare for common info */ -/* */ /* Declare for common info */ -/* */ -#define MAX_PATH_NUM_92CS 2 struct odm_phy_info { u8 RxPWDBAll; u8 SignalQuality; /* in 0-100 index. */ - u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */ - u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* in 0~100 index */ + u8 RxMIMOSignalQuality[RF_PATH_MAX]; /* EVM */ + u8 RxMIMOSignalStrength[RF_PATH_MAX];/* in 0~100 index */ s8 RxPower; /* in dBm Translate from PWdB */ s8 RecvSignalPower;/* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */ u8 BTRxRSSIPercentage; u8 SignalStrength; /* in 0-100 index. */ - u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */ - u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */ + u8 RxPwr[RF_PATH_MAX];/* per-path's pwdb */ + u8 RxSNR[RF_PATH_MAX];/* per-path's SNR */ }; struct odm_phy_dbg_info { /* ODM Write,debug info */ - s8 RxSNRdB[MAX_PATH_NUM_92CS]; + s8 RxSNRdB[RF_PATH_MAX]; u64 NumQryPhyStatus; u64 NumQryPhyStatusCCK; u64 NumQryPhyStatusOFDM; /* Others */ - s32 RxEVM[MAX_PATH_NUM_92CS]; + s32 RxEVM[RF_PATH_MAX]; }; diff --git a/drivers/staging/rtl8723au/include/odm_HWConfig.h b/drivers/staging/rtl8723au/include/odm_HWConfig.h index 057fdb012a47..147855c96ad4 100644 --- a/drivers/staging/rtl8723au/include/odm_HWConfig.h +++ b/drivers/staging/rtl8723au/include/odm_HWConfig.h @@ -74,21 +74,21 @@ struct phy_rx_agc_info { }; struct phy_status_rpt { - struct phy_rx_agc_info path_agc[2]; - u8 ch_corr[2]; + struct phy_rx_agc_info path_agc[RF_PATH_MAX]; + u8 ch_corr[RF_PATH_MAX]; u8 cck_sig_qual_ofdm_pwdb_all; u8 cck_agc_rpt_ofdm_cfosho_a; u8 cck_rpt_b_ofdm_cfosho_b; u8 rsvd_1;/* ch_corr_msb; */ u8 noise_power_db_msb; - u8 path_cfotail[2]; - u8 pcts_mask[2]; - s8 stream_rxevm[2]; - u8 path_rxsnr[2]; + u8 path_cfotail[RF_PATH_MAX]; + u8 pcts_mask[RF_PATH_MAX]; + s8 stream_rxevm[RF_PATH_MAX]; + u8 path_rxsnr[RF_PATH_MAX]; u8 noise_power_db_lsb; u8 rsvd_2[3]; - u8 stream_csi[2]; - u8 stream_target_csi[2]; + u8 stream_csi[RF_PATH_MAX]; + u8 stream_target_csi[RF_PATH_MAX]; s8 sig_evm; u8 rsvd_3; diff --git a/drivers/staging/rtl8723au/include/osdep_service.h b/drivers/staging/rtl8723au/include/osdep_service.h index cb7b5cdcbe55..039bc7285ed0 100644 --- a/drivers/staging/rtl8723au/include/osdep_service.h +++ b/drivers/staging/rtl8723au/include/osdep_service.h @@ -149,70 +149,6 @@ extern unsigned char MCS_rate_1R23A[16]; void _rtw_init_queue23a(struct rtw_queue *pqueue); u32 _rtw_queue_empty23a(struct rtw_queue *pqueue); -u32 rtw_get_current_time(void); -u32 rtw_systime_to_ms23a(u32 systime); -u32 rtw_ms_to_systime23a(u32 ms); -s32 rtw_get_passing_time_ms23a(u32 start); -s32 rtw_get_time_interval_ms23a(u32 start, u32 end); - -#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) -#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2) - -static inline u32 _RND4(u32 sz) -{ - - u32 val; - - val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2; - - return val; - -} - -static inline u32 _RND8(u32 sz) -{ - - u32 val; - - val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3; - - return val; - -} - -static inline u32 _RND128(u32 sz) -{ - - u32 val; - - val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7; - - return val; - -} - -static inline u32 _RND256(u32 sz) -{ - - u32 val; - - val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8; - - return val; - -} - -static inline u32 _RND512(u32 sz) -{ - - u32 val; - - val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9; - - return val; - -} - static inline u32 bitshift(u32 bitmask) { u32 i; @@ -223,20 +159,11 @@ static inline u32 bitshift(u32 bitmask) return i; } -#define STRUCT_PACKED __attribute__ ((packed)) - -/* limitation of path length */ -#define PATH_LENGTH_MAX PATH_MAX - void rtw_suspend_lock_init(void); void rtw_suspend_lock_uninit(void); void rtw_lock_suspend(void); void rtw_unlock_suspend(void); -/* File operation APIs, just for linux now */ -int rtw_is_file_readable(char *path); -int rtw_retrive_from_file(char *path, u8* buf, u32 sz); -int rtw_store_to_file(char *path, u8* buf, u32 sz); #define NDEV_FMT "%s" #define NDEV_ARG(ndev) ndev->name @@ -255,69 +182,9 @@ u64 rtw_division6423a(u64 x, u64 y); /* Macros for handling unaligned memory accesses */ -#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) -#define RTW_PUT_BE16(a, val) \ - do { \ - (a)[0] = ((u16) (val)) >> 8; \ - (a)[1] = ((u16) (val)) & 0xff; \ - } while (0) - -#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) -#define RTW_PUT_LE16(a, val) \ - do { \ - (a)[1] = ((u16) (val)) >> 8; \ - (a)[0] = ((u16) (val)) & 0xff; \ - } while (0) - #define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ((u32) (a)[2])) -#define RTW_PUT_BE24(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[2] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ - (((u32) (a)[2]) << 8) | ((u32) (a)[3])) -#define RTW_PUT_BE32(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[3] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ - (((u32) (a)[1]) << 8) | ((u32) (a)[0])) -#define RTW_PUT_LE32(a, val) \ - do { \ - (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[0] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ - (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ - (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ - (((u64) (a)[6]) << 8) | ((u64) (a)[7])) -#define RTW_PUT_BE64(a, val) \ - do { \ - (a)[0] = (u8) (((u64) (val)) >> 56); \ - (a)[1] = (u8) (((u64) (val)) >> 48); \ - (a)[2] = (u8) (((u64) (val)) >> 40); \ - (a)[3] = (u8) (((u64) (val)) >> 32); \ - (a)[4] = (u8) (((u64) (val)) >> 24); \ - (a)[5] = (u8) (((u64) (val)) >> 16); \ - (a)[6] = (u8) (((u64) (val)) >> 8); \ - (a)[7] = (u8) (((u64) (val)) & 0xff); \ - } while (0) -#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ - (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ - (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ - (((u64) (a)[1]) << 8) | ((u64) (a)[0])) struct rtw_cbuf { u32 write; diff --git a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h index 5777eda01403..6d1edc6ef84d 100644 --- a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h +++ b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h @@ -1074,7 +1074,7 @@ struct packet_irp_acl_data { struct packet_irp_hcievent_data { u8 EventCode; u8 Length; - u8 Data[5]; + u8 Data[20]; }; struct common_triple { @@ -1332,7 +1332,7 @@ struct bt_coexist_8723a { u8 c2hBtInfoOriginal; u8 prec2hBtInfo; /* for 1Ant */ u8 bC2hBtInquiryPage; - u64 btInqPageStartTime; /* for 2Ant */ + unsigned long btInqPageStartTime; /* for 2Ant */ u8 c2hBtProfile; /* for 1Ant */ u8 btRetryCnt; u8 btInfoExt; diff --git a/drivers/staging/rtl8723au/include/rtl8723a_pg.h b/drivers/staging/rtl8723au/include/rtl8723a_pg.h index 12f7a1326b4c..5c2ec448e568 100644 --- a/drivers/staging/rtl8723au/include/rtl8723a_pg.h +++ b/drivers/staging/rtl8723au/include/rtl8723a_pg.h @@ -15,9 +15,7 @@ #ifndef __RTL8723A_PG_H__ #define __RTL8723A_PG_H__ -/* */ /* EEPROM/Efuse PG Offset for 8723E/8723U/8723S */ -/* */ #define EEPROM_CCK_TX_PWR_INX_8723A 0x10 #define EEPROM_HT40_1S_TX_PWR_INX_8723A 0x16 #define EEPROM_HT20_TX_PWR_INX_DIFF_8723A 0x1C @@ -53,31 +51,24 @@ /* RTL8723AS */ #define EEPROM_MAC_ADDR_8723AS 0xAA -/* */ /* EEPROM/Efuse Value Type */ -/* */ #define EETYPE_TX_PWR 0x0 -/* */ /* EEPROM/Efuse Default Value */ -/* */ #define EEPROM_Default_CrystalCap_8723A 0x20 -/* */ /* EEPROM/EFUSE data structure definition. */ -/* */ -#define MAX_RF_PATH_NUM 2 #define MAX_CHNL_GROUP 3+9 struct txpowerinfo { - u8 CCKIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 HT40_1SIndex[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 HT40_2SIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 HT20IndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 OFDMIndexDiff[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 HT40MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; - u8 HT20MaxOffset[MAX_RF_PATH_NUM][MAX_CHNL_GROUP]; + u8 CCKIndex[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 HT40_1SIndex[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 HT40_2SIndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 HT20IndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 OFDMIndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 HT40MaxOffset[RF_PATH_MAX][MAX_CHNL_GROUP]; + u8 HT20MaxOffset[RF_PATH_MAX][MAX_CHNL_GROUP]; u8 TSSI_A[3]; u8 TSSI_B[3]; u8 TSSI_A_5G[3]; /* 5GL/5GM/5GH */ diff --git a/drivers/staging/rtl8723au/include/rtw_mlme.h b/drivers/staging/rtl8723au/include/rtw_mlme.h index adbea44d601f..31f96f39b498 100644 --- a/drivers/staging/rtl8723au/include/rtw_mlme.h +++ b/drivers/staging/rtl8723au/include/rtw_mlme.h @@ -379,6 +379,28 @@ struct mlme_priv { u8 *wps_probe_req_ie; u32 wps_probe_req_ie_len; + u8 *assoc_req; + u32 assoc_req_len; + u32 assoc_rsp_len; + u8 *assoc_rsp; + u32 wps_assoc_resp_ie_len; + u8 *wps_assoc_resp_ie; + u8 *wps_probe_resp_ie; + u32 wps_probe_resp_ie_len; + u8 *wps_beacon_ie; + u32 wps_beacon_ie_len; + u32 p2p_go_probe_resp_ie_len; /* for GO */ + u32 p2p_assoc_req_ie_len; + u8 *p2p_beacon_ie; + u8 *p2p_probe_req_ie; + u8 *p2p_probe_resp_ie; + u8 *p2p_go_probe_resp_ie; /* for GO */ + u8 *p2p_assoc_req_ie; + u32 p2p_beacon_ie_len; + u32 p2p_probe_req_ie_len; + u32 p2p_probe_resp_ie_len; + u8 *wfd_assoc_req_ie; + u32 wfd_assoc_req_ie_len; #ifdef CONFIG_8723AU_AP_MODE /* Number of associated Non-ERP stations (i.e., stations using 802.11b @@ -407,50 +429,20 @@ struct mlme_priv { u16 ht_op_mode; - u8 *assoc_req; - u32 assoc_req_len; - u8 *assoc_rsp; - u32 assoc_rsp_len; - - u8 *wps_beacon_ie; - /* u8 *wps_probe_req_ie; */ - u8 *wps_probe_resp_ie; - u8 *wps_assoc_resp_ie; - - u32 wps_beacon_ie_len; - /* u32 wps_probe_req_ie_len; */ - u32 wps_probe_resp_ie_len; - u32 wps_assoc_resp_ie_len; - - u8 *p2p_beacon_ie; - u8 *p2p_probe_req_ie; - u8 *p2p_probe_resp_ie; - u8 *p2p_go_probe_resp_ie; /* for GO */ - u8 *p2p_assoc_req_ie; - - u32 p2p_beacon_ie_len; - u32 p2p_probe_req_ie_len; - u32 p2p_probe_resp_ie_len; - u32 p2p_go_probe_resp_ie_len; /* for GO */ - u32 p2p_assoc_req_ie_len; spinlock_t bcn_update_lock; u8 update_bcn; #endif /* ifdef CONFIG_8723AU_AP_MODE */ -#if defined(CONFIG_8723AU_P2P) u8 *wfd_beacon_ie; u8 *wfd_probe_req_ie; u8 *wfd_probe_resp_ie; u8 *wfd_go_probe_resp_ie; /* for GO */ - u8 *wfd_assoc_req_ie; u32 wfd_beacon_ie_len; u32 wfd_probe_req_ie_len; u32 wfd_probe_resp_ie_len; u32 wfd_go_probe_resp_ie_len; /* for GO */ - u32 wfd_assoc_req_ie_len; -#endif }; #ifdef CONFIG_8723AU_AP_MODE diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h index d1c2d71295e5..0aaf0d5d8aea 100644 --- a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h @@ -451,9 +451,7 @@ struct mlme_ext_priv { u64 TSFValue; -#ifdef CONFIG_8723AU_AP_MODE unsigned char bstart_bss; -#endif u8 update_channel_plan_by_ap_done; /* recv_decache check for Action_public frame */ u8 action_public_dialog_token; diff --git a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h index b42e14198e8d..e0da87d4d3d6 100644 --- a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h @@ -180,7 +180,7 @@ struct pwrctrl_priv { u8 ips_mode; u8 ips_mode_req; /* used to accept the mode setting request */ uint bips_processing; - u32 ips_deny_time; /* will deny IPS when system time is smaller */ + unsigned long ips_deny_time; /* deny IPS when system time is smaller */ u8 ps_processing; /* used to mark whether in rtw_ps_processor23a */ u8 bLeisurePs; diff --git a/drivers/staging/rtl8723au/include/rtw_recv.h b/drivers/staging/rtl8723au/include/rtw_recv.h index e2462e052e44..d1866a6e831f 100644 --- a/drivers/staging/rtl8723au/include/rtw_recv.h +++ b/drivers/staging/rtl8723au/include/rtw_recv.h @@ -17,6 +17,7 @@ #include #include +#include #define NR_RECVFRAME 256 @@ -75,13 +76,11 @@ struct signal_stat { u32 total_val; /* sum of valid elements */ }; -#define MAX_PATH_NUM_92CS 2 - struct phy_info { u8 RxPWDBAll; u8 SignalQuality; /* in 0-100 index. */ - u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */ - u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* 0~100 */ + u8 RxMIMOSignalQuality[RF_PATH_MAX]; /* EVM */ + u8 RxMIMOSignalStrength[RF_PATH_MAX];/* 0~100 */ s8 RxPower; /* in dBm Translate from PWdB */ /* Real power in dBm for this packet, no beautification and aggregation. * Keep this raw info to be used for the other procedures. @@ -89,8 +88,8 @@ struct phy_info { s8 RecvSignalPower; u8 BTRxRSSIPercentage; u8 SignalStrength; /* in 0-100 index. */ - u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */ - u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */ + u8 RxPwr[RF_PATH_MAX];/* per-path's pwdb */ + u8 RxSNR[RF_PATH_MAX];/* per-path's SNR */ }; diff --git a/drivers/staging/rtl8723au/include/sta_info.h b/drivers/staging/rtl8723au/include/sta_info.h index 8af98ee77b07..ffbc9e3f2156 100644 --- a/drivers/staging/rtl8723au/include/sta_info.h +++ b/drivers/staging/rtl8723au/include/sta_info.h @@ -140,8 +140,6 @@ struct sta_info { /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */ /* sta_info: (AP & STA) CAP/INFO */ -#ifdef CONFIG_8723AU_AP_MODE - struct list_head asoc_list; struct list_head auth_list; @@ -183,11 +181,12 @@ struct sta_info { u8 has_legacy_ac; unsigned int sleepq_ac_len; -#ifdef CONFIG_8723AU_P2P /* p2p priv data */ u8 is_p2p_device; u8 p2p_status_code; + u8 keep_alive_trycnt; + /* p2p client info */ u8 dev_addr[ETH_ALEN]; u8 dev_cap; @@ -197,12 +196,6 @@ struct sta_info { u8 secdev_types_list[32];/* 32/8 == 4; */ u16 dev_name_len; u8 dev_name[32]; -#endif /* CONFIG_8723AU_P2P */ - - u8 keep_alive_trycnt; - -#endif /* CONFIG_8723AU_AP_MODE */ - u8 *passoc_req; u32 assoc_req_len; @@ -329,9 +322,6 @@ struct sta_priv { struct rtw_queue wakeup_q; struct rtw_adapter *padapter; - - -#ifdef CONFIG_8723AU_AP_MODE struct list_head asoc_list; struct list_head auth_list; spinlock_t asoc_list_lock; @@ -357,7 +347,6 @@ struct sta_priv { u16 max_num_sta; struct wlan_acl_pool acl_list; -#endif }; static inline u32 wifi_mac_hash(u8 *mac) diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 1c99616f51ac..50840b9a11fa 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -1495,9 +1495,11 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter, int ret = 0; uint wps_ielen = 0; u8 *wps_ie; +#ifdef CONFIG_8723AU_P2P u32 p2p_ielen = 0; u8 *p2p_ie; u32 wfd_ielen = 0; +#endif struct mlme_priv *pmlmepriv = &padapter->mlmepriv; #ifdef CONFIG_DEBUG_CFG80211 @@ -1595,12 +1597,12 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT]; struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; -#ifdef CONFIG_8723AU_P2P - struct wifidirect_info *pwdinfo = &padapter->wdinfo; -#endif /* CONFIG_8723AU_P2P */ struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev); struct cfg80211_ssid *ssids = request->ssids; +#ifdef CONFIG_8723AU_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; int social_channel = 0; +#endif /* CONFIG_8723AU_P2P */ bool need_indicate_scan_done = false; #ifdef CONFIG_DEBUG_CFG80211 @@ -1625,8 +1627,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy, goto check_need_indicate_scan_done; } #ifdef CONFIG_8723AU_P2P - if (ssids->ssid != NULL && - !memcmp(ssids->ssid, "DIRECT-", 7) && + if (!memcmp(ssids->ssid, "DIRECT-", 7) && rtw_get_p2p_ie23a((u8 *) request->ie, request->ie_len, NULL, NULL)) { if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE); @@ -2738,7 +2739,9 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; u32 len = skb->len; u8 category, action; +#ifdef CONFIG_8723AU_P2P int type = -1; +#endif if (rtw_action_frame_parse23a(skb->data, len, &category, &action) == false) { @@ -2760,7 +2763,9 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, else DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, action); +#ifdef CONFIG_8723AU_P2P dump: +#endif /* starting alloc mgmt frame to dump it */ pmgntframe = alloc_mgtxmitframe23a(pxmitpriv); if (pmgntframe == NULL) @@ -2971,8 +2976,10 @@ static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head, int ret = 0; u8 *pbuf = NULL; uint len, wps_ielen = 0; +#ifdef CONFIG_8723AU_P2P uint p2p_ielen = 0; u8 got_p2p_ie = false; +#endif struct mlme_priv *pmlmepriv = &adapter->mlmepriv; /* struct sta_priv *pstapriv = &padapter->stapriv; */ @@ -3245,7 +3252,9 @@ static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, uint frame_len) { +#ifdef CONFIG_8723AU_P2P int type; +#endif s32 freq; int channel; u8 category, action; @@ -3261,7 +3270,9 @@ void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame, rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); +#ifdef CONFIG_8723AU_P2P indicate: +#endif if (channel <= RTW_CH_MAX_2G_CHANNEL) freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); @@ -3276,7 +3287,9 @@ indicate: void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, u8 *pmgmt_frame, uint frame_len) { +#ifdef CONFIG_8723AU_P2P int type; +#endif s32 freq; int channel; u8 category, action; @@ -3298,7 +3311,9 @@ void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter, rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action); DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action); +#ifdef CONFIG_8723AU_P2P indicate: +#endif if (channel <= RTW_CH_MAX_2G_CHANNEL) freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); @@ -3485,7 +3500,7 @@ void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY; /* Length: */ - RTW_PUT_LE16(p2p_ie + p2pielen, 0x0002); + put_unaligned_le16(0x0002, p2p_ie + p2pielen); p2pielen += 2; /* Value: */ @@ -3499,7 +3514,7 @@ void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter, p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO; /* Length: */ - RTW_PUT_LE16(p2p_ie + p2pielen, devinfo_contentlen); + put_unaligned_le16(devinfo_contentlen, p2p_ie + p2pielen); p2pielen += 2; /* Value: */ @@ -3580,7 +3595,9 @@ static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy, del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); +#ifdef CONFIG_8723AU_P2P p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); +#endif } pcfg80211_wdinfo->is_ro_ch = true; @@ -3663,7 +3680,9 @@ static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy, if (pcfg80211_wdinfo->is_ro_ch == true) { DBG_8723A("%s, cancel ro ch timer\n", __func__); del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer); +#ifdef CONFIG_8723AU_P2P p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK); +#endif } rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); @@ -3834,7 +3853,9 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category, action); +#ifdef CONFIG_8723AU_P2P dump: +#endif do { dump_cnt++; tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len); @@ -3890,10 +3911,14 @@ static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, int ret = 0; uint wps_ielen = 0; u8 *wps_ie; +#ifdef CONFIG_8723AU_P2P u32 p2p_ielen = 0; - u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 }; - u8 *p2p_ie; u32 wfd_ielen = 0; + u8 *p2p_ie; +#endif +#ifdef CONFIG_8723AU_AP_MODE + u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 }; +#endif struct rtw_adapter *padapter = netdev_priv(ndev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; @@ -3923,8 +3948,10 @@ static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen); pmlmepriv->wps_beacon_ie_len = wps_ielen; +#ifdef CONFIG_8723AU_AP_MODE update_beacon23a(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true); +#endif } #ifdef CONFIG_8723AU_P2P p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen); @@ -3992,12 +4019,14 @@ static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, { struct rtw_adapter *padapter = netdev_priv(net); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - int ret = 0; - uint wps_ielen = 0; - u8 *wps_ie; +#ifdef CONFIG_8723AU_P2P u32 p2p_ielen = 0; u8 *p2p_ie; u32 wfd_ielen = 0; +#endif + int ret = 0; + uint wps_ielen = 0; + u8 *wps_ie; if (len > 0) { wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen); @@ -4176,7 +4205,9 @@ int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, { int ret = 0; uint wps_ielen = 0; +#ifdef CONFIG_8723AU_P2P u32 p2p_ielen = 0; +#endif #ifdef CONFIG_DEBUG_CFG80211 DBG_8723A("%s, ielen =%d\n", __func__, len); diff --git a/drivers/staging/rtl8723au/os_dep/osdep_service.c b/drivers/staging/rtl8723au/os_dep/osdep_service.c index aeb48db0ee8c..97fc27dce19c 100644 --- a/drivers/staging/rtl8723au/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723au/os_dep/osdep_service.c @@ -71,260 +71,6 @@ u32 _rtw_queue_empty23a(struct rtw_queue *pqueue) return false; } -u32 rtw_get_current_time(void) -{ - return jiffies; -} - -inline u32 rtw_systime_to_ms23a(u32 systime) -{ - return systime * 1000 / HZ; -} - -inline u32 rtw_ms_to_systime23a(u32 ms) -{ - return ms * HZ / 1000; -} - -/* the input parameter start use the same unit as returned - * by rtw_get_current_time - */ -inline s32 rtw_get_passing_time_ms23a(u32 start) -{ - return rtw_systime_to_ms23a(jiffies-start); -} - -inline s32 rtw_get_time_interval_ms23a(u32 start, u32 end) -{ - return rtw_systime_to_ms23a(end-start); -} - -#define RTW_SUSPEND_LOCK_NAME "rtw_wifi" - -inline void rtw_suspend_lock_init(void) -{ -} - -inline void rtw_suspend_lock_uninit(void) -{ -} - -inline void rtw_lock_suspend(void) -{ -} - -inline void rtw_unlock_suspend(void) -{ -} - -/* Open a file with the specific @param path, @param flag, @param mode - * @param fpp the pointer of struct file pointer to get struct - * file pointer while file opening is success - * @param path the path of the file to open - * @param flag file operation flags, please refer to linux document - * @param mode please refer to linux document - * @return Linux specific error code - */ -static int openFile(struct file **fpp, char *path, int flag, int mode) -{ - struct file *fp; - - fp = filp_open(path, flag, mode); - if (IS_ERR(fp)) { - *fpp = NULL; - return PTR_ERR(fp); - } else { - *fpp = fp; - return 0; - } -} - -/* Close the file with the specific @param fp - * @param fp the pointer of struct file to close - * @return always 0 - */ -static int closeFile(struct file *fp) -{ - filp_close(fp, NULL); - return 0; -} - -static int readFile(struct file *fp, char *buf, int len) -{ - int rlen = 0, sum = 0; - - if (!fp->f_op || !fp->f_op->read) - return -EPERM; - - while (sum < len) { - rlen = fp->f_op->read(fp, buf+sum, len-sum, &fp->f_pos); - if (rlen > 0) - sum += rlen; - else if (0 != rlen) - return rlen; - else - break; - } - return sum; -} - -static int writeFile(struct file *fp, char *buf, int len) -{ - int wlen = 0, sum = 0; - - if (!fp->f_op || !fp->f_op->write) - return -EPERM; - - while (sum < len) { - wlen = fp->f_op->write(fp, buf+sum, len-sum, &fp->f_pos); - if (wlen > 0) - sum += wlen; - else if (0 != wlen) - return wlen; - else - break; - } - return sum; -} - -/* Test if the specifi @param path is a file and readable - * @param path the path of the file to test - * @return Linux specific error code - */ -static int isFileReadable(char *path) -{ - struct file *fp; - int ret = 0; - mm_segment_t oldfs; - char buf; - - fp = filp_open(path, O_RDONLY, 0); - if (IS_ERR(fp)) { - ret = PTR_ERR(fp); - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (1 != readFile(fp, &buf, 1)) - ret = PTR_ERR(fp); - - set_fs(oldfs); - filp_close(fp, NULL); - } - return ret; -} - -/* Open the file with @param path and retrive the file content into - * memory starting from @param buf for @param sz at most - * @param path the path of the file to open and read - * @param buf the starting address of the buffer to store file content - * @param sz how many bytes to read at most - * @return the byte we've read, or Linux specific error code - */ -static int retriveFromFile(char *path, u8 *buf, u32 sz) -{ - int ret = -1; - mm_segment_t oldfs; - struct file *fp; - - if (path && buf) { - ret = openFile(&fp, path, O_RDONLY, 0); - if (!ret) { - DBG_8723A("%s openFile path:%s fp =%p\n", - __func__, path, fp); - - oldfs = get_fs(); set_fs(get_ds()); - ret = readFile(fp, buf, sz); - set_fs(oldfs); - closeFile(fp); - - DBG_8723A("%s readFile, ret:%d\n", __func__, ret); - } else { - DBG_8723A("%s openFile path:%s Fail, ret:%d\n", - __func__, path, ret); - } - } else { - DBG_8723A("%s NULL pointer\n", __func__); - ret = -EINVAL; - } - return ret; -} - -/* Open the file with @param path and wirte @param sz byte of data starting - * from @param buf into the file - * @param path the path of the file to open and write - * @param buf the starting address of the data to write into file - * @param sz how many bytes to write at most - * @return the byte we've written, or Linux specific error code - */ -static int storeToFile(char *path, u8 *buf, u32 sz) -{ - struct file *fp; - int ret = 0; - mm_segment_t oldfs; - - if (path && buf) { - ret = openFile(&fp, path, O_CREAT|O_WRONLY, 0666); - if (!ret) { - DBG_8723A("%s openFile path:%s fp =%p\n", __func__, - path, fp); - - oldfs = get_fs(); set_fs(get_ds()); - ret = writeFile(fp, buf, sz); - set_fs(oldfs); - closeFile(fp); - - DBG_8723A("%s writeFile, ret:%d\n", __func__, ret); - } else { - DBG_8723A("%s openFile path:%s Fail, ret:%d\n", - __func__, path, ret); - } - } else { - DBG_8723A("%s NULL pointer\n", __func__); - ret = -EINVAL; - } - return ret; -} - -/* -* Test if the specifi @param path is a file and readable -* @param path the path of the file to test -* @return true or false -*/ -int rtw_is_file_readable(char *path) -{ - if (isFileReadable(path) == 0) - return true; - else - return false; -} - -/* Open the file with @param path and retrive the file content into memoryi - * starting from @param buf for @param sz at most - * @param path the path of the file to open and read - * @param buf the starting address of the buffer to store file content - * @param sz how many bytes to read at most - * @return the byte we've read - */ -int rtw_retrive_from_file(char *path, u8 *buf, u32 sz) -{ - int ret = retriveFromFile(path, buf, sz); - return ret >= 0 ? ret : 0; -} - -/* Open the file with @param path and wirte @param sz byte of - * data starting from @param buf into the file - * @param path the path of the file to open and write - * @param buf the starting address of the data to write into file - * @param sz how many bytes to write at most - * @return the byte we've written - */ -int rtw_store_to_file(char *path, u8 *buf, u32 sz) -{ - int ret = storeToFile(path, buf, sz); - return ret >= 0 ? ret : 0; -} - u64 rtw_modular6423a(u64 x, u64 y) { return do_div(x, y); diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c index 040bf29b9d06..612806e0de2e 100644 --- a/drivers/staging/rtl8723au/os_dep/usb_intf.c +++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c @@ -664,8 +664,10 @@ static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, /* set mac addr */ rtw_macaddr_cfg23a(padapter->eeprompriv.mac_addr); +#ifdef CONFIG_8723AU_P2P rtw_init_wifidirect_addrs23a(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); +#endif DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n", padapter->bDriverStopped, padapter->bSurpriseRemoved, @@ -811,12 +813,9 @@ static void rtw_disconnect(struct usb_interface *pusb_intf) return; } -extern int console_suspend_enabled; - static int __init rtw_drv_entry(void) { RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n")); - rtw_suspend_lock_init(); return usb_register(usb_drv); } @@ -825,8 +824,6 @@ static void __exit rtw_drv_halt(void) RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n")); DBG_8723A("+rtw_drv_halt\n"); - rtw_suspend_lock_uninit(); - usb_deregister(usb_drv); DBG_8723A("-rtw_drv_halt\n"); -- cgit v1.2.3 From 9176303c404741b2f96796466437f2badf6e289b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Mar 2014 21:37:43 -0500 Subject: staging: r8723au: Turn on build of new driver This commit also creates a TODO file. Signed-off-by: Larry Finger Cc: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 ++ drivers/staging/Makefile | 1 + drivers/staging/rtl8723au/Kconfig | 37 ++++++++++++++++++++++++ drivers/staging/rtl8723au/Makefile | 58 ++++++++++++++++++++++++++++++++++++++ drivers/staging/rtl8723au/TODO | 13 +++++++++ 5 files changed, 111 insertions(+) create mode 100644 drivers/staging/rtl8723au/Kconfig create mode 100644 drivers/staging/rtl8723au/Makefile create mode 100644 drivers/staging/rtl8723au/TODO (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 47cf17543008..ea5efb426f75 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -50,6 +50,8 @@ source "drivers/staging/rtl8712/Kconfig" source "drivers/staging/rtl8188eu/Kconfig" +source "drivers/staging/rtl8723au/Kconfig" + source "drivers/staging/rtl8821ae/Kconfig" source "drivers/staging/rts5139/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index d12f6189db46..86e020c2ad0d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += rtl8188eu/ +obj-$(CONFIG_R8723AU) += rtl8723au/ obj-$(CONFIG_R8821AE) += rtl8821ae/ obj-$(CONFIG_RTS5139) += rts5139/ obj-$(CONFIG_RTS5208) += rts5208/ diff --git a/drivers/staging/rtl8723au/Kconfig b/drivers/staging/rtl8723au/Kconfig new file mode 100644 index 000000000000..7f19d1566290 --- /dev/null +++ b/drivers/staging/rtl8723au/Kconfig @@ -0,0 +1,37 @@ +config R8723AU + tristate "Realtek RTL8723AU Wireless LAN NIC driver" + depends on WLAN && USB + select WIRELESS_EXT + select WEXT_PRIV + default n + ---help--- + This option adds the Realtek RTL8723AU USB device such as found in + the Lenovo Yogi 13 tablet. If built as a module, it will be called r8723au. + +if R8723AU + +config 8723AU_AP_MODE + bool "Realtek RTL8723AU AP mode" + default y + ---help--- + This option enables Access Point mode. Unless you know that your system + will never be used as an AP, or the target system has limited memory, + "Y" should be selected. + +config 8723AU_P2P + bool "Realtek RTL8723AU Peer-to-peer mode" + default y + ---help--- + This option enables peer-to-peer mode for the r8723au driver. Unless you + know that peer-to-peer (P2P) mode will never be used, or the target system has + limited memory, "Y" should be selected. + +config 8723AU_BT_COEXIST + bool "Realtek RTL8723AU BlueTooth Coexistence" + default y + ---help--- + This option enables icoexistence with BlueTooth communications for the r8723au driver. + Unless you know that this driver will never by used with BT, or the target system has + limited memory, "Y" should be selected. + +endif diff --git a/drivers/staging/rtl8723au/Makefile b/drivers/staging/rtl8723au/Makefile new file mode 100644 index 000000000000..11c6dd486462 --- /dev/null +++ b/drivers/staging/rtl8723au/Makefile @@ -0,0 +1,58 @@ +r8723au-y := \ + core/rtw_ap.o \ + core/rtw_cmd.o \ + core/rtw_efuse.o \ + core/rtw_io.o \ + core/rtw_ioctl_set.o \ + core/rtw_ieee80211.o \ + core/rtw_led.o \ + core/rtw_mlme.o \ + core/rtw_mlme_ext.o \ + core/rtw_p2p.o \ + core/rtw_pwrctrl.o \ + core/rtw_recv.o \ + core/rtw_security.o \ + core/rtw_sreset.o \ + core/rtw_sta_mgt.o \ + core/rtw_xmit.o \ + core/rtw_wlan_util.o \ + hal/hal_com.o \ + hal/hal_intf.o \ + hal/Hal8723PwrSeq.o \ + hal/Hal8723UHWImg_CE.o \ + hal/HalDMOutSrc8723A_CE.o \ + hal/HalHWImg8723A_BB.o \ + hal/HalHWImg8723A_MAC.o \ + hal/HalHWImg8723A_RF.o \ + hal/HalPwrSeqCmd.o \ + hal/odm_RegConfig8723A.o \ + hal/rtl8723a_bt-coexist.o \ + hal/odm_debug.o \ + hal/odm_interface.o \ + hal/odm_HWConfig.o \ + hal/odm.o \ + hal/rtl8723a_cmd.o \ + hal/rtl8723a_dm.o \ + hal/rtl8723a_hal_init.o \ + hal/rtl8723a_phycfg.o \ + hal/rtl8723a_rf6052.o \ + hal/rtl8723a_rxdesc.o \ + hal/rtl8723a_sreset.o \ + hal/rtl8723a_xmit.o \ + hal/rtl8723au_led.o \ + hal/rtl8723au_recv.o \ + hal/rtl8723au_xmit.o \ + hal/usb_halinit.o \ + hal/usb_ops_linux.o \ + os_dep/ioctl_cfg80211.o \ + os_dep/mlme_linux.o \ + os_dep/osdep_service.o \ + os_dep/os_intfs.o \ + os_dep/recv_linux.o \ + os_dep/usb_intf.o \ + os_dep/usb_ops_linux.o \ + os_dep/xmit_linux.o + +obj-$(CONFIG_R8723AU) := r8723au.o + +ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/include diff --git a/drivers/staging/rtl8723au/TODO b/drivers/staging/rtl8723au/TODO new file mode 100644 index 000000000000..175a0ceb7421 --- /dev/null +++ b/drivers/staging/rtl8723au/TODO @@ -0,0 +1,13 @@ +TODO: +- find and remove code valid only for 5 HGz. Many of the obvious + ones have been removed, but things like channel > 14 still exist. +- find and remove any code for other chips that is left over +- convert any remaining unusual variable types +- find codes that can use %pM and %Nph formatting +- checkpatch.pl fixes - most of the remaining ones are lines too long. Many + of them will require refactoring +- merge Realtek's bugfixes and new features into the driver +- switch to use MAC80211 + +Please send any patches to Greg Kroah-Hartman , +Jes Sorensen , and Larry Finger . -- cgit v1.2.3 From 36c4d5c250a9243fee1045bb25b3e06d844015fa Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 5 Apr 2014 22:48:59 -0500 Subject: staging: r8723au: Fix randconfig build errors The kbuild test robot got the following errors for i386-randconfig-c0-04060652: ERROR: "wiphy_free" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "bridge_tunnel_header" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "ieee80211_frequency_to_channel" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_rx_mgmt" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "ieee80211_channel_to_frequency" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_mgmt_tx_status" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "rfc1042_header" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "__ieee80211_get_channel" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "wiphy_unregister" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_connect_result" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_michael_mic_failure" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_roamed" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_put_bss" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "wiphy_new" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "wiphy_register" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_inform_bss_width_frame" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_disconnected" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "ieee80211_amsdu_to_8023s" [drivers/staging/rtl8723au/r8723au.ko] undefined! ERROR: "cfg80211_scan_done" [drivers/staging/rtl8723au/r8723au.ko] undefined! All of these are fixed by forcing the selection of CFG80211 in Kconfig. Reported-by: kbuild test robot Signed-off-by: Larry Finger Cc: Jes Sorensen Cc: kbuild-all@01.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/Kconfig b/drivers/staging/rtl8723au/Kconfig index 7f19d1566290..78e8805938ee 100644 --- a/drivers/staging/rtl8723au/Kconfig +++ b/drivers/staging/rtl8723au/Kconfig @@ -3,6 +3,7 @@ config R8723AU depends on WLAN && USB select WIRELESS_EXT select WEXT_PRIV + select CFG80211 default n ---help--- This option adds the Realtek RTL8723AU USB device such as found in -- cgit v1.2.3 From f004e559470518e7c1bf47379ee5f6d624541440 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 6 Apr 2014 19:42:03 -0500 Subject: staging: r8723au: Fix build problem when RFKILL is not selected The kbuild test robot reports the following build errors for x86_64-randconfig-c1-0407: All error/warnings: net/built-in.o: In function `wiphy_new': >> (.text+0x7684c): undefined reference to `rfkill_alloc' net/built-in.o: In function `wiphy_rfkill_start_polling': >> (.text+0x76da4): undefined reference to `rfkill_resume_polling' net/built-in.o: In function `wiphy_rfkill_stop_polling': >> (.text+0x76de9): undefined reference to `rfkill_pause_polling' net/built-in.o: In function `wiphy_unregister': >> (.text+0x76ec9): undefined reference to `rfkill_unregister' net/built-in.o: In function `wiphy_rfkill_set_hw_state': >> (.text+0x771bc): undefined reference to `rfkill_set_hw_state' net/built-in.o: In function `wiphy_register': >> (.text+0x77968): undefined reference to `rfkill_register' net/built-in.o: In function `wiphy_register': >> (.text+0x77981): undefined reference to `rfkill_destroy' net/built-in.o: In function `cfg80211_rfkill_sync_work': >> core.c:(.text+0x788ad): undefined reference to `rfkill_blocked' net/built-in.o: In function `cfg80211_dev_free': >> (.text+0x78a7b): undefined reference to `rfkill_destroy' net/built-in.o: In function `cfg80211_netdev_notifier_call': >> core.c:(.text+0x79203): undefined reference to `rfkill_blocked' net/built-in.o: In function `nl80211_start_p2p_device': These undefined sysbols are all satisfied if a "select RFKILL" is added to Kconfig. This "fix" leads to another problem as follows: >> nl80211.c:(.text+0x9032e): undefined reference to `rfkill_blocked' net/rfkill/Kconfig:4:error: recursive dependency detected! net/rfkill/Kconfig:4: symbol RFKILL is selected by R8723AU drivers/staging/rtl8723au/Kconfig:1: symbol R8723AU depends on USB drivers/usb/Kconfig:41: symbol USB is selected by MOUSE_APPLETOUCH drivers/input/mouse/Kconfig:162: symbol MOUSE_APPLETOUCH depends on INPUT drivers/input/Kconfig:8: symbol INPUT is selected by ACPI_CMPC drivers/platform/x86/Kconfig:635: symbol ACPI_CMPC depends on RFKILL To avoid substituting one build error for another, I added a "depends on RFKILL". My suspicion is that this particular error is caused by a kbuild bug, or that the selection of INPUT by ACPI_CMPC is wrong. In any case, that will be solved separately. Reported-by: kbuild test robot Signed-off-by: Larry Finger Cc: Jes Sorensen Cc: kbuild-all@01.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/Kconfig b/drivers/staging/rtl8723au/Kconfig index 78e8805938ee..07fb5e4e50fa 100644 --- a/drivers/staging/rtl8723au/Kconfig +++ b/drivers/staging/rtl8723au/Kconfig @@ -1,6 +1,6 @@ config R8723AU tristate "Realtek RTL8723AU Wireless LAN NIC driver" - depends on WLAN && USB + depends on USB && WLAN && RFKILL select WIRELESS_EXT select WEXT_PRIV select CFG80211 -- cgit v1.2.3 From 9c01e83ce71158e48148c0aba2d8b78d89e28b97 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sun, 30 Mar 2014 01:42:07 +0900 Subject: staging: unisys: Add missing close parentheses in filexfer.c Add missing close parentheses in filexfer.c Signed-off-by: Masanari Iida Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorchipset/filexfer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorchipset/filexfer.c b/drivers/staging/unisys/visorchipset/filexfer.c index 431cff844a43..f950d6e85b5f 100644 --- a/drivers/staging/unisys/visorchipset/filexfer.c +++ b/drivers/staging/unisys/visorchipset/filexfer.c @@ -83,7 +83,7 @@ struct any_request { * coarsest possible alignment boundary that could be required * for any user data structure. */ - u8 caller_context_data[1] __aligned(sizeof(ulong2); + u8 caller_context_data[1] __aligned(sizeof(ulong2)); }; /* -- cgit v1.2.3 From b0e2796029d26f4541e9cb1e9f54e1a7020618c6 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 4 Apr 2014 14:38:24 -0400 Subject: Staging: unisys: verify that a control channel exists The code didn't verify that a control channel exists before trying to use it. It caused NULL ptr derefs which were easy to trigger by an unpriviliged user simply by reading the proc file, causing: [ 68.161404] BUG: unable to handle kernel NULL pointer dereference at (null) [ 68.162442] IP: visorchannel_read (drivers/staging/unisys/visorchannel/visorchannel_funcs.c:225) [ 68.163165] PGD 5ca21067 PUD 5ca20067 PMD 0 [ 68.163712] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC [ 68.164390] Dumping ftrace buffer: [ 68.164793] (ftrace buffer empty) [ 68.165220] Modules linked in: [ 68.165601] CPU: 0 PID: 7915 Comm: cat Tainted: G W 3.14.0-next-20140403-sasha-00012-gef5fa7d-dirty #373 [ 68.166821] task: ffff88006e8c3000 ti: ffff88005ca30000 task.ti: ffff88005ca30000 [ 68.167689] RIP: visorchannel_read (drivers/staging/unisys/visorchannel/visorchannel_funcs.c:225) [ 68.168683] RSP: 0018:ffff88005ca31e58 EFLAGS: 00010282 [ 68.169302] RAX: ffff88005ca10000 RBX: ffff88005ca31e97 RCX: 0000000000000001 [ 68.170019] RDX: ffff88005ca31e97 RSI: 0000000000000bd6 RDI: 0000000000000000 [ 68.170019] RBP: ffff88005ca31e78 R08: 0000000000000000 R09: 0000000000000000 [ 68.170019] R10: ffff880000000000 R11: 0000000000000001 R12: 0000000000000001 [ 68.170019] R13: 0000000000000bd6 R14: 0000000000000000 R15: 0000000000008000 [ 68.170019] FS: 00007f0e8c041700(0000) GS:ffff88007be00000(0000) knlGS:0000000000000000 [ 68.170019] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 68.170019] CR2: 0000000000000000 CR3: 000000006efe9000 CR4: 00000000000006b0 [ 68.170019] Stack: [ 68.170019] ffff88005ca31f50 ffff88005ca10000 000000000060e000 ffff88005ca31f50 [ 68.170019] ffff88005ca31ec8 ffffffff83e6f983 ffff8800780db810 0000000000008000 [ 68.170019] ffff88005ca31ec8 ffff88006da5f908 ffff8800780db800 000000000060e000 [ 68.170019] Call Trace: [ 68.170019] proc_read_toolaction (drivers/staging/unisys/visorchipset/visorchipset_main.c:2541) [ 68.170019] proc_reg_read (fs/proc/inode.c:211) [ 68.170019] vfs_read (fs/read_write.c:408) [ 68.170019] SyS_read (fs/read_write.c:519 fs/read_write.c:511) [ 68.170019] tracesys (arch/x86/kernel/entry_64.S:749) [ 68.170019] Code: 00 00 66 66 66 66 90 55 48 89 e5 48 83 ec 20 48 89 5d e0 48 89 d3 4c 89 65 e8 49 89 cc 4c 89 6d f0 49 89 f5 4c 89 75 f8 49 89 fe <48> 8b 3f e8 4f f9 ff ff 85 c0 0f 88 97 00 00 00 4d 85 ed 0f 85 [ 68.170019] RIP visorchannel_read (drivers/staging/unisys/visorchannel/visorchannel_funcs.c:225) [ 68.170019] RSP [ 68.170019] CR2: 0000000000000000 Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../staging/unisys/visorchipset/visorchipset_main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c index 8252ca14695d..257c6e59b460 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset_main.c +++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c @@ -2414,6 +2414,9 @@ proc_read_installer(struct file *file, char __user *buf, char *vbuf; loff_t pos = *offset; + if (!ControlVm_channel) + return -ENODEV; + if (pos < 0) return -EINVAL; @@ -2463,6 +2466,9 @@ proc_write_installer(struct file *file, U16 remainingSteps; U32 error, textId; + if (!ControlVm_channel) + return -ENODEV; + /* Check to make sure there is no buffer overflow */ if (count > (sizeof(buf) - 1)) return -EINVAL; @@ -2524,6 +2530,9 @@ proc_read_toolaction(struct file *file, char __user *buf, char *vbuf; loff_t pos = *offset; + if (!ControlVm_channel) + return -ENODEV; + if (pos < 0) return -EINVAL; @@ -2562,6 +2571,9 @@ proc_write_toolaction(struct file *file, char buf[3]; U8 toolAction; + if (!ControlVm_channel) + return -ENODEV; + /* Check to make sure there is no buffer overflow */ if (count > (sizeof(buf) - 1)) return -EINVAL; @@ -2601,6 +2613,9 @@ proc_read_bootToTool(struct file *file, char __user *buf, char *vbuf; loff_t pos = *offset; + if (!ControlVm_channel) + return -ENODEV; + if (pos < 0) return -EINVAL; @@ -2639,6 +2654,9 @@ proc_write_bootToTool(struct file *file, int inputVal; ULTRA_EFI_SPAR_INDICATION efiSparIndication; + if (!ControlVm_channel) + return -ENODEV; + /* Check to make sure there is no buffer overflow */ if (count > (sizeof(buf) - 1)) return -EINVAL; -- cgit v1.2.3 From 806192c07d889ab4821e396793bbcc4c7f2fad94 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Apr 2014 12:49:36 -0700 Subject: Staging: unisys: mark drivers as BROKEN Turns out these drivers like to mess around with the system even if the hardware they control isn't present. That's not good, and people are starting to report lots of issues with this in their build/boot testing. So for now, let's just mark them as BROKEN, until the code gets converted to use the proper driver model interaction (i.e. don't do anything until the hardware is actually found in the system.) Reported-by: Fengguang Wu Reported-by: Sasha Levin Cc: Benjamin Romer Cc: David Kershner Cc: someone Cc: Ken Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig index ac080c9dcf46..6bae2afbaa15 100644 --- a/drivers/staging/unisys/Kconfig +++ b/drivers/staging/unisys/Kconfig @@ -3,7 +3,7 @@ # menuconfig UNISYSSPAR bool "Unisys SPAR driver support" - depends on X86_64 + depends on X86_64 && BROKEN ---help--- Support for the Unisys SPAR drivers -- cgit v1.2.3 From dda26427bd5252cbea876fe8a80050943c0dc642 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 7 Apr 2014 21:13:01 +0200 Subject: staging: rtl8723au: The 8723 only has two paths Converting the driver from the original RTL provided version, by error converted the code to use four, which caused all sorts of issues. The confusion was caused by the RTL driver having support for both two and four paths, and in some places had RF_PATH_MAX = 3. At the same time it kept the data structures hard coded for two paths, in particular the ones matching the efuse data. Signed-off-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c | 35 ---------------------- drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c | 8 ----- drivers/staging/rtl8723au/include/Hal8723APhyCfg.h | 2 -- 3 files changed, 45 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c index bac3f3bd5311..8400e6e2fca8 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c @@ -462,20 +462,12 @@ phy_InitBBRFRegisterDefinition(struct rtw_adapter *Adapter) pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; - /* 16 LSBs if read 32-bit from 0x874 */ - pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW; - /* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ - pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW; /* RF Interface Readback Value */ /* 16 LSBs if read 32-bit from 0x8E0 */ pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB; - /* 16 LSBs if read 32-bit from 0x8E4 */ - pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB; - /* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ - pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB; /* RF Interface Output (and Enable) */ /* 16 LSBs if read 32-bit from 0x860 */ @@ -497,14 +489,10 @@ phy_InitBBRFRegisterDefinition(struct rtw_adapter *Adapter) /* BB Band Select */ pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; - pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; - pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; - pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; - pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tranceiver A~D HSSI Parameter-1 */ /* wire control parameter1 */ @@ -523,63 +511,40 @@ phy_InitBBRFRegisterDefinition(struct rtw_adapter *Adapter) rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */ pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; - pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = - rFPGA0_XCD_SwitchControl; - pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = - rFPGA0_XCD_SwitchControl; /* AGC control 1 */ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; - pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; - pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; /* AGC control 2 */ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; - pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; - pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; /* RX AFE control 1 */ pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; - pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; - pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; /* RX AFE control 1 */ pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE; pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; - pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; - pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; /* Tx AFE control 1 */ pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; - pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; - pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; /* Tx AFE control 2 */ pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE; pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; - pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; - pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; /* Tranceiver LSSI Readback SI mode */ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; - pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; - pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; /* Tranceiver LSSI Readback PI mode */ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; - /* pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBackPi = - rFPGA0_XC_LSSIReadBack; */ - /* pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBackPi = - rFPGA0_XD_LSSIReadBack; */ - } /* The following is for High Power PA */ diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c b/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c index 2a7238bacdc8..ed39c18c3f84 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c @@ -434,11 +434,9 @@ static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter) /*----Store original RFENV control type----*/ switch (eRFPath) { case RF_PATH_A: - case RF_PATH_C: u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); break; case RF_PATH_B: - case RF_PATH_D: u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); break; } @@ -468,20 +466,14 @@ static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter) if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile23a(&pHalData->odmpriv, (enum RF_RADIO_PATH)eRFPath, (enum RF_RADIO_PATH)eRFPath)) rtStatus = _FAIL; break; - case RF_PATH_C: - break; - case RF_PATH_D: - break; } /*----Restore RFENV control type----*/; switch (eRFPath) { case RF_PATH_A: - case RF_PATH_C: PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); break; case RF_PATH_B: - case RF_PATH_D: PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); break; } diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h index 1478d311683a..4b7f3479c0a9 100644 --- a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h +++ b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h @@ -60,8 +60,6 @@ enum HW90_BLOCK { enum RF_RADIO_PATH { RF_PATH_A = 0, /* Radio Path A */ RF_PATH_B = 1, /* Radio Path B */ - RF_PATH_C = 2, /* Radio Path C */ - RF_PATH_D = 3, /* Radio Path D */ RF_PATH_MAX /* Max RF number 90 support */ }; -- cgit v1.2.3