diff options
-rw-r--r-- | drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index fb2bb042683a..911155843655 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6624,6 +6624,91 @@ error: return ret; } +static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv) +{ + u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN]; + u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2]; + struct rtl8xxxu_vif *rtlvif; + struct ieee80211_vif *vif; + u8 tsftr[8], tsftr_1[8]; + int i; + + msr = rtl8xxxu_read8(priv, REG_MSR); + bcn_ctrl = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + bcn_ctrl_1 = rtl8xxxu_read8(priv, REG_BEACON_CTRL_1); + + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + atimwnd[i] = rtl8xxxu_read8(priv, REG_ATIMWND + i); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + atimwnd_1[i] = rtl8xxxu_read8(priv, REG_ATIMWND_1 + i); + + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr[i] = rtl8xxxu_read8(priv, REG_TSFTR + i); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr_1[i] = rtl8xxxu_read8(priv, REG_TSFTR1 + i); + + for (i = 0; i < ARRAY_SIZE(macid); i++) + macid[i] = rtl8xxxu_read8(priv, REG_MACID + i); + + for (i = 0; i < ARRAY_SIZE(bssid); i++) + bssid[i] = rtl8xxxu_read8(priv, REG_BSSID + i); + + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + macid_1[i] = rtl8xxxu_read8(priv, REG_MACID1 + i); + + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + bssid_1[i] = rtl8xxxu_read8(priv, REG_BSSID1 + i); + + /* disable bcn function, disable update TSF */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, (bcn_ctrl & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, (bcn_ctrl_1 & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + + /* switch msr */ + msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2); + rtl8xxxu_write8(priv, REG_MSR, msr); + + /* write port0 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1 & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + rtl8xxxu_write8(priv, REG_ATIMWND + i, atimwnd_1[i]); + for (i = 0; i < ARRAY_SIZE(tsftr_1); i++) + rtl8xxxu_write8(priv, REG_TSFTR + i, tsftr_1[i]); + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + rtl8xxxu_write8(priv, REG_MACID + i, macid_1[i]); + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + rtl8xxxu_write8(priv, REG_BSSID + i, bssid_1[i]); + + /* write port1 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + rtl8xxxu_write8(priv, REG_ATIMWND_1 + i, atimwnd[i]); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + rtl8xxxu_write8(priv, REG_TSFTR1 + i, tsftr[i]); + for (i = 0; i < ARRAY_SIZE(macid); i++) + rtl8xxxu_write8(priv, REG_MACID1 + i, macid[i]); + for (i = 0; i < ARRAY_SIZE(bssid); i++) + rtl8xxxu_write8(priv, REG_BSSID1 + i, bssid[i]); + + /* write bcn ctl */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl); + + vif = priv->vifs[0]; + priv->vifs[0] = priv->vifs[1]; + priv->vifs[1] = vif; + + /* priv->vifs[0] is NULL here, based on how this function is currently + * called from rtl8xxxu_add_interface(). + * When this function will be used in the future for a different + * scenario, please check whether vifs[0] or vifs[1] can be NULL and if + * necessary add code to set port_num = 1. + */ + rtlvif = (struct rtl8xxxu_vif *)priv->vifs[1]->drv_priv; + rtlvif->port_num = 1; +} + static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -6651,8 +6736,10 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, } break; case NL80211_IFTYPE_AP: - if (port_num == 1) - return -EOPNOTSUPP; + if (port_num == 1) { + rtl8xxxu_switch_ports(priv); + port_num = 0; + } rtl8xxxu_write8(priv, REG_BEACON_CTRL, BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID); |