.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * RTL8XXXU mac80211 USB driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * rtl8723au driver. As the Realtek 8xxx chips are very similar in |
---|
11 | 12 | * their programming interface, I have started adding support for |
---|
12 | 13 | * additional 8xxx chips like the 8192cu, 8188cus, etc. |
---|
13 | | - * |
---|
14 | | - * This program is free software; you can redistribute it and/or modify it |
---|
15 | | - * under the terms of version 2 of the GNU General Public License as |
---|
16 | | - * published by the Free Software Foundation. |
---|
17 | | - * |
---|
18 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
19 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
20 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
21 | | - * more details. |
---|
22 | 14 | */ |
---|
23 | 15 | |
---|
24 | 16 | #include <linux/init.h> |
---|
.. | .. |
---|
1153 | 1145 | switch (hw->conf.chandef.width) { |
---|
1154 | 1146 | case NL80211_CHAN_WIDTH_20_NOHT: |
---|
1155 | 1147 | ht = false; |
---|
| 1148 | + /* fall through */ |
---|
1156 | 1149 | case NL80211_CHAN_WIDTH_20: |
---|
1157 | 1150 | opmode |= BW_OPMODE_20MHZ; |
---|
1158 | 1151 | rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode); |
---|
.. | .. |
---|
1262 | 1255 | void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw) |
---|
1263 | 1256 | { |
---|
1264 | 1257 | struct rtl8xxxu_priv *priv = hw->priv; |
---|
1265 | | - u32 val32, rsr; |
---|
| 1258 | + u32 val32; |
---|
1266 | 1259 | u8 val8, subchannel; |
---|
1267 | 1260 | u16 rf_mode_bw; |
---|
1268 | 1261 | bool ht = true; |
---|
.. | .. |
---|
1271 | 1264 | |
---|
1272 | 1265 | rf_mode_bw = rtl8xxxu_read16(priv, REG_WMAC_TRXPTCL_CTL); |
---|
1273 | 1266 | rf_mode_bw &= ~WMAC_TRXPTCL_CTL_BW_MASK; |
---|
1274 | | - rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); |
---|
1275 | 1267 | channel = hw->conf.chandef.chan->hw_value; |
---|
1276 | 1268 | |
---|
1277 | 1269 | /* Hack */ |
---|
.. | .. |
---|
1280 | 1272 | switch (hw->conf.chandef.width) { |
---|
1281 | 1273 | case NL80211_CHAN_WIDTH_20_NOHT: |
---|
1282 | 1274 | ht = false; |
---|
| 1275 | + /* fall through */ |
---|
1283 | 1276 | case NL80211_CHAN_WIDTH_20: |
---|
1284 | 1277 | rf_mode_bw |= WMAC_TRXPTCL_CTL_BW_20; |
---|
1285 | 1278 | subchannel = 0; |
---|
.. | .. |
---|
1748 | 1741 | case 3: |
---|
1749 | 1742 | priv->ep_tx_low_queue = 1; |
---|
1750 | 1743 | priv->ep_tx_count++; |
---|
| 1744 | + /* fall through */ |
---|
1751 | 1745 | case 2: |
---|
1752 | 1746 | priv->ep_tx_normal_queue = 1; |
---|
1753 | 1747 | priv->ep_tx_count++; |
---|
| 1748 | + /* fall through */ |
---|
1754 | 1749 | case 1: |
---|
1755 | 1750 | priv->ep_tx_high_queue = 1; |
---|
1756 | 1751 | priv->ep_tx_count++; |
---|
.. | .. |
---|
1879 | 1874 | |
---|
1880 | 1875 | /* We have 8 bits to indicate validity */ |
---|
1881 | 1876 | map_addr = offset * 8; |
---|
1882 | | - if (map_addr >= EFUSE_MAP_LEN) { |
---|
1883 | | - dev_warn(dev, "%s: Illegal map_addr (%04x), " |
---|
1884 | | - "efuse corrupt!\n", |
---|
1885 | | - __func__, map_addr); |
---|
1886 | | - ret = -EINVAL; |
---|
1887 | | - goto exit; |
---|
1888 | | - } |
---|
1889 | 1877 | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
---|
1890 | 1878 | /* Check word enable condition in the section */ |
---|
1891 | 1879 | if (word_mask & BIT(i)) { |
---|
.. | .. |
---|
1896 | 1884 | ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &val8); |
---|
1897 | 1885 | if (ret) |
---|
1898 | 1886 | goto exit; |
---|
| 1887 | + if (map_addr >= EFUSE_MAP_LEN - 1) { |
---|
| 1888 | + dev_warn(dev, "%s: Illegal map_addr (%04x), " |
---|
| 1889 | + "efuse corrupt!\n", |
---|
| 1890 | + __func__, map_addr); |
---|
| 1891 | + ret = -EINVAL; |
---|
| 1892 | + goto exit; |
---|
| 1893 | + } |
---|
1899 | 1894 | priv->efuse_wifi.raw[map_addr++] = val8; |
---|
1900 | 1895 | |
---|
1901 | 1896 | ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &val8); |
---|
.. | .. |
---|
2930 | 2925 | } |
---|
2931 | 2926 | |
---|
2932 | 2927 | if (!(simubitmap & 0x30) && priv->tx_paths > 1) { |
---|
2933 | | - /* path B RX OK */ |
---|
| 2928 | + /* path B TX OK */ |
---|
2934 | 2929 | for (i = 4; i < 6; i++) |
---|
2935 | 2930 | result[3][i] = result[c1][i]; |
---|
2936 | 2931 | } |
---|
2937 | 2932 | |
---|
2938 | | - if (!(simubitmap & 0x30) && priv->tx_paths > 1) { |
---|
| 2933 | + if (!(simubitmap & 0xc0) && priv->tx_paths > 1) { |
---|
2939 | 2934 | /* path B RX OK */ |
---|
2940 | 2935 | for (i = 6; i < 8; i++) |
---|
2941 | 2936 | result[3][i] = result[c1][i]; |
---|
.. | .. |
---|
3119 | 3114 | u32 i, val32; |
---|
3120 | 3115 | int path_a_ok, path_b_ok; |
---|
3121 | 3116 | int retry = 2; |
---|
3122 | | - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { |
---|
| 3117 | + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { |
---|
3123 | 3118 | REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, |
---|
3124 | 3119 | REG_RX_WAIT_CCA, REG_TX_CCK_RFON, |
---|
3125 | 3120 | REG_TX_CCK_BBON, REG_TX_OFDM_RFON, |
---|
.. | .. |
---|
3129 | 3124 | REG_RX_TO_RX, REG_STANDBY, |
---|
3130 | 3125 | REG_SLEEP, REG_PMPD_ANAEN |
---|
3131 | 3126 | }; |
---|
3132 | | - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { |
---|
| 3127 | + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { |
---|
3133 | 3128 | REG_TXPAUSE, REG_BEACON_CTRL, |
---|
3134 | 3129 | REG_BEACON_CTRL_1, REG_GPIO_MUXCFG |
---|
3135 | 3130 | }; |
---|
3136 | | - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { |
---|
| 3131 | + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { |
---|
3137 | 3132 | REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, |
---|
3138 | 3133 | REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, |
---|
3139 | 3134 | REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, |
---|
.. | .. |
---|
3824 | 3819 | rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); |
---|
3825 | 3820 | } |
---|
3826 | 3821 | |
---|
3827 | | -#ifdef NEED_PS_TDMA |
---|
3828 | | -static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, |
---|
3829 | | - u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) |
---|
| 3822 | +void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, |
---|
| 3823 | + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) |
---|
3830 | 3824 | { |
---|
3831 | 3825 | struct h2c_cmd h2c; |
---|
3832 | 3826 | |
---|
.. | .. |
---|
3839 | 3833 | h2c.b_type_dma.data5 = arg5; |
---|
3840 | 3834 | rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma)); |
---|
3841 | 3835 | } |
---|
3842 | | -#endif |
---|
3843 | 3836 | |
---|
3844 | 3837 | void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv) |
---|
3845 | 3838 | { |
---|
.. | .. |
---|
3895 | 3888 | |
---|
3896 | 3889 | /* Check if MAC is already powered on */ |
---|
3897 | 3890 | val8 = rtl8xxxu_read8(priv, REG_CR); |
---|
| 3891 | + val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR); |
---|
3898 | 3892 | |
---|
3899 | 3893 | /* |
---|
3900 | 3894 | * Fix 92DU-VC S3 hang with the reason is that secondary mac is not |
---|
3901 | 3895 | * initialized. First MAC returns 0xea, second MAC returns 0x00 |
---|
3902 | 3896 | */ |
---|
3903 | | - if (val8 == 0xea) |
---|
| 3897 | + if (val8 == 0xea || !(val16 & SYS_CLK_MAC_CLK_ENABLE)) |
---|
3904 | 3898 | macpower = false; |
---|
3905 | 3899 | else |
---|
3906 | 3900 | macpower = true; |
---|
.. | .. |
---|
4310 | 4304 | rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); |
---|
4311 | 4305 | } |
---|
4312 | 4306 | |
---|
4313 | | -void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, int sgi) |
---|
| 4307 | +void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, |
---|
| 4308 | + u32 ramask, u8 rateid, int sgi) |
---|
4314 | 4309 | { |
---|
4315 | 4310 | struct h2c_cmd h2c; |
---|
4316 | 4311 | |
---|
.. | .. |
---|
4330 | 4325 | } |
---|
4331 | 4326 | |
---|
4332 | 4327 | void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, |
---|
4333 | | - u32 ramask, int sgi) |
---|
| 4328 | + u32 ramask, u8 rateid, int sgi) |
---|
4334 | 4329 | { |
---|
4335 | 4330 | struct h2c_cmd h2c; |
---|
4336 | | - u8 bw = 0; |
---|
| 4331 | + u8 bw = RTL8XXXU_CHANNEL_WIDTH_20; |
---|
4337 | 4332 | |
---|
4338 | 4333 | memset(&h2c, 0, sizeof(struct h2c_cmd)); |
---|
4339 | 4334 | |
---|
.. | .. |
---|
4343 | 4338 | h2c.b_macid_cfg.ramask2 = (ramask >> 16) & 0xff; |
---|
4344 | 4339 | h2c.b_macid_cfg.ramask3 = (ramask >> 24) & 0xff; |
---|
4345 | 4340 | |
---|
4346 | | - h2c.ramask.arg = 0x80; |
---|
4347 | | - h2c.b_macid_cfg.data1 = 0; |
---|
| 4341 | + h2c.b_macid_cfg.data1 = rateid; |
---|
4348 | 4342 | if (sgi) |
---|
4349 | 4343 | h2c.b_macid_cfg.data1 |= BIT(7); |
---|
4350 | 4344 | |
---|
4351 | 4345 | h2c.b_macid_cfg.data2 = bw; |
---|
4352 | 4346 | |
---|
4353 | | - dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x, size %zi\n", |
---|
4354 | | - __func__, ramask, h2c.ramask.arg, sizeof(h2c.b_macid_cfg)); |
---|
| 4347 | + dev_dbg(&priv->udev->dev, "%s: rate mask %08x, rateid %02x, sgi %d, size %zi\n", |
---|
| 4348 | + __func__, ramask, rateid, sgi, sizeof(h2c.b_macid_cfg)); |
---|
4355 | 4349 | rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.b_macid_cfg)); |
---|
4356 | 4350 | } |
---|
4357 | 4351 | |
---|
.. | .. |
---|
4484 | 4478 | rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); |
---|
4485 | 4479 | } |
---|
4486 | 4480 | |
---|
| 4481 | +static u16 |
---|
| 4482 | +rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) |
---|
| 4483 | +{ |
---|
| 4484 | + u16 network_type = WIRELESS_MODE_UNKNOWN; |
---|
| 4485 | + |
---|
| 4486 | + if (hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) { |
---|
| 4487 | + if (sta->vht_cap.vht_supported) |
---|
| 4488 | + network_type = WIRELESS_MODE_AC; |
---|
| 4489 | + else if (sta->ht_cap.ht_supported) |
---|
| 4490 | + network_type = WIRELESS_MODE_N_5G; |
---|
| 4491 | + |
---|
| 4492 | + network_type |= WIRELESS_MODE_A; |
---|
| 4493 | + } else { |
---|
| 4494 | + if (sta->vht_cap.vht_supported) |
---|
| 4495 | + network_type = WIRELESS_MODE_AC; |
---|
| 4496 | + else if (sta->ht_cap.ht_supported) |
---|
| 4497 | + network_type = WIRELESS_MODE_N_24G; |
---|
| 4498 | + |
---|
| 4499 | + if (sta->supp_rates[0] <= 0xf) |
---|
| 4500 | + network_type |= WIRELESS_MODE_B; |
---|
| 4501 | + else if (sta->supp_rates[0] & 0xf) |
---|
| 4502 | + network_type |= (WIRELESS_MODE_B | WIRELESS_MODE_G); |
---|
| 4503 | + else |
---|
| 4504 | + network_type |= WIRELESS_MODE_G; |
---|
| 4505 | + } |
---|
| 4506 | + |
---|
| 4507 | + return network_type; |
---|
| 4508 | +} |
---|
| 4509 | + |
---|
| 4510 | +static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) |
---|
| 4511 | +{ |
---|
| 4512 | + u32 reg_edca_param[IEEE80211_NUM_ACS] = { |
---|
| 4513 | + [IEEE80211_AC_VO] = REG_EDCA_VO_PARAM, |
---|
| 4514 | + [IEEE80211_AC_VI] = REG_EDCA_VI_PARAM, |
---|
| 4515 | + [IEEE80211_AC_BE] = REG_EDCA_BE_PARAM, |
---|
| 4516 | + [IEEE80211_AC_BK] = REG_EDCA_BK_PARAM, |
---|
| 4517 | + }; |
---|
| 4518 | + u32 val32; |
---|
| 4519 | + u16 wireless_mode = 0; |
---|
| 4520 | + u8 aifs, aifsn, sifs; |
---|
| 4521 | + int i; |
---|
| 4522 | + |
---|
| 4523 | + if (priv->vif) { |
---|
| 4524 | + struct ieee80211_sta *sta; |
---|
| 4525 | + |
---|
| 4526 | + rcu_read_lock(); |
---|
| 4527 | + sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid); |
---|
| 4528 | + if (sta) |
---|
| 4529 | + wireless_mode = rtl8xxxu_wireless_mode(priv->hw, sta); |
---|
| 4530 | + rcu_read_unlock(); |
---|
| 4531 | + } |
---|
| 4532 | + |
---|
| 4533 | + if (priv->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ || |
---|
| 4534 | + (wireless_mode & WIRELESS_MODE_N_24G)) |
---|
| 4535 | + sifs = 16; |
---|
| 4536 | + else |
---|
| 4537 | + sifs = 10; |
---|
| 4538 | + |
---|
| 4539 | + for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
---|
| 4540 | + val32 = rtl8xxxu_read32(priv, reg_edca_param[i]); |
---|
| 4541 | + |
---|
| 4542 | + /* It was set in conf_tx. */ |
---|
| 4543 | + aifsn = val32 & 0xff; |
---|
| 4544 | + |
---|
| 4545 | + /* aifsn not set yet or already fixed */ |
---|
| 4546 | + if (aifsn < 2 || aifsn > 15) |
---|
| 4547 | + continue; |
---|
| 4548 | + |
---|
| 4549 | + aifs = aifsn * slot_time + sifs; |
---|
| 4550 | + |
---|
| 4551 | + val32 &= ~0xff; |
---|
| 4552 | + val32 |= aifs; |
---|
| 4553 | + rtl8xxxu_write32(priv, reg_edca_param[i], val32); |
---|
| 4554 | + } |
---|
| 4555 | +} |
---|
| 4556 | + |
---|
4487 | 4557 | static void |
---|
4488 | 4558 | rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
---|
4489 | 4559 | struct ieee80211_bss_conf *bss_conf, u32 changed) |
---|
.. | .. |
---|
4526 | 4596 | sgi = 1; |
---|
4527 | 4597 | rcu_read_unlock(); |
---|
4528 | 4598 | |
---|
4529 | | - priv->fops->update_rate_mask(priv, ramask, sgi); |
---|
| 4599 | + priv->vif = vif; |
---|
| 4600 | + priv->rssi_level = RTL8XXXU_RATR_STA_INIT; |
---|
| 4601 | + |
---|
| 4602 | + priv->fops->update_rate_mask(priv, ramask, 0, sgi); |
---|
4530 | 4603 | |
---|
4531 | 4604 | rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); |
---|
4532 | 4605 | |
---|
.. | .. |
---|
4566 | 4639 | else |
---|
4567 | 4640 | val8 = 20; |
---|
4568 | 4641 | rtl8xxxu_write8(priv, REG_SLOT, val8); |
---|
| 4642 | + |
---|
| 4643 | + rtl8xxxu_set_aifs(priv, val8); |
---|
4569 | 4644 | } |
---|
4570 | 4645 | |
---|
4571 | 4646 | if (changed & BSS_CHANGED_BSSID) { |
---|
.. | .. |
---|
4778 | 4853 | struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); |
---|
4779 | 4854 | struct rtl8xxxu_priv *priv = hw->priv; |
---|
4780 | 4855 | struct device *dev = &priv->udev->dev; |
---|
| 4856 | + u8 *qc = ieee80211_get_qos_ctl(hdr); |
---|
| 4857 | + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
---|
4781 | 4858 | u32 rate; |
---|
4782 | 4859 | u16 rate_flags = tx_info->control.rates[0].flags; |
---|
4783 | 4860 | u16 seq_number; |
---|
.. | .. |
---|
4789 | 4866 | rate = tx_rate->hw_value; |
---|
4790 | 4867 | |
---|
4791 | 4868 | if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) |
---|
4792 | | - dev_info(dev, "%s: TX rate: %d, pkt size %d\n", |
---|
4793 | | - __func__, rate, cpu_to_le16(tx_desc->pkt_size)); |
---|
| 4869 | + dev_info(dev, "%s: TX rate: %d, pkt size %u\n", |
---|
| 4870 | + __func__, rate, le16_to_cpu(tx_desc->pkt_size)); |
---|
4794 | 4871 | |
---|
4795 | 4872 | seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
---|
4796 | 4873 | |
---|
.. | .. |
---|
4801 | 4878 | |
---|
4802 | 4879 | tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT); |
---|
4803 | 4880 | |
---|
4804 | | - if (ampdu_enable) |
---|
| 4881 | + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) |
---|
4805 | 4882 | tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_ENABLE); |
---|
4806 | 4883 | else |
---|
4807 | 4884 | tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_BREAK); |
---|
.. | .. |
---|
4849 | 4926 | struct rtl8xxxu_priv *priv = hw->priv; |
---|
4850 | 4927 | struct device *dev = &priv->udev->dev; |
---|
4851 | 4928 | struct rtl8xxxu_txdesc40 *tx_desc40; |
---|
| 4929 | + u8 *qc = ieee80211_get_qos_ctl(hdr); |
---|
| 4930 | + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
---|
4852 | 4931 | u32 rate; |
---|
4853 | 4932 | u16 rate_flags = tx_info->control.rates[0].flags; |
---|
4854 | 4933 | u16 seq_number; |
---|
.. | .. |
---|
4862 | 4941 | rate = tx_rate->hw_value; |
---|
4863 | 4942 | |
---|
4864 | 4943 | if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) |
---|
4865 | | - dev_info(dev, "%s: TX rate: %d, pkt size %d\n", |
---|
4866 | | - __func__, rate, cpu_to_le16(tx_desc40->pkt_size)); |
---|
| 4944 | + dev_info(dev, "%s: TX rate: %d, pkt size %u\n", |
---|
| 4945 | + __func__, rate, le16_to_cpu(tx_desc40->pkt_size)); |
---|
4867 | 4946 | |
---|
4868 | 4947 | seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
---|
4869 | 4948 | |
---|
.. | .. |
---|
4875 | 4954 | |
---|
4876 | 4955 | tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC40_SEQ_SHIFT); |
---|
4877 | 4956 | |
---|
4878 | | - if (ampdu_enable) |
---|
| 4957 | + if (ampdu_enable && test_bit(tid, priv->tid_tx_operational)) |
---|
4879 | 4958 | tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE); |
---|
4880 | 4959 | else |
---|
4881 | 4960 | tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK); |
---|
.. | .. |
---|
4921 | 5000 | struct device *dev = &priv->udev->dev; |
---|
4922 | 5001 | u32 queue, rts_rate; |
---|
4923 | 5002 | u16 pktlen = skb->len; |
---|
4924 | | - u16 seq_number; |
---|
4925 | 5003 | u16 rate_flag = tx_info->control.rates[0].flags; |
---|
4926 | 5004 | int tx_desc_size = priv->fops->tx_desc_size; |
---|
4927 | 5005 | int ret; |
---|
4928 | | - bool usedesc40, ampdu_enable, sgi = false, short_preamble = false; |
---|
| 5006 | + bool ampdu_enable, sgi = false, short_preamble = false; |
---|
4929 | 5007 | |
---|
4930 | 5008 | if (skb_headroom(skb) < tx_desc_size) { |
---|
4931 | 5009 | dev_warn(dev, |
---|
.. | .. |
---|
4949 | 5027 | if (ieee80211_is_action(hdr->frame_control)) |
---|
4950 | 5028 | rtl8xxxu_dump_action(dev, hdr); |
---|
4951 | 5029 | |
---|
4952 | | - usedesc40 = (tx_desc_size == 40); |
---|
4953 | 5030 | tx_info->rate_driver_data[0] = hw; |
---|
4954 | 5031 | |
---|
4955 | 5032 | if (control && control->sta) |
---|
4956 | 5033 | sta = control->sta; |
---|
| 5034 | + |
---|
| 5035 | + queue = rtl8xxxu_queue_select(hw, skb); |
---|
4957 | 5036 | |
---|
4958 | 5037 | tx_desc = skb_push(skb, tx_desc_size); |
---|
4959 | 5038 | |
---|
.. | .. |
---|
4967 | 5046 | is_broadcast_ether_addr(ieee80211_get_DA(hdr))) |
---|
4968 | 5047 | tx_desc->txdw0 |= TXDESC_BROADMULTICAST; |
---|
4969 | 5048 | |
---|
4970 | | - queue = rtl8xxxu_queue_select(hw, skb); |
---|
4971 | 5049 | tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT); |
---|
4972 | 5050 | |
---|
4973 | 5051 | if (tx_info->control.hw_key) { |
---|
.. | .. |
---|
4990 | 5068 | if (ieee80211_is_data_qos(hdr->frame_control) && sta) { |
---|
4991 | 5069 | if (sta->ht_cap.ht_supported) { |
---|
4992 | 5070 | u32 ampdu, val32; |
---|
| 5071 | + u8 *qc = ieee80211_get_qos_ctl(hdr); |
---|
| 5072 | + u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
---|
4993 | 5073 | |
---|
4994 | 5074 | ampdu = (u32)sta->ht_cap.ampdu_density; |
---|
4995 | 5075 | val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT; |
---|
4996 | 5076 | tx_desc->txdw2 |= cpu_to_le32(val32); |
---|
4997 | 5077 | |
---|
4998 | 5078 | ampdu_enable = true; |
---|
| 5079 | + |
---|
| 5080 | + if (!test_bit(tid, priv->tx_aggr_started) && |
---|
| 5081 | + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) |
---|
| 5082 | + if (!ieee80211_start_tx_ba_session(sta, tid, 0)) |
---|
| 5083 | + set_bit(tid, priv->tx_aggr_started); |
---|
4999 | 5084 | } |
---|
5000 | 5085 | } |
---|
5001 | 5086 | |
---|
.. | .. |
---|
5016 | 5101 | else |
---|
5017 | 5102 | rts_rate = 0; |
---|
5018 | 5103 | |
---|
5019 | | - seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
---|
5020 | 5104 | |
---|
5021 | 5105 | priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, |
---|
5022 | 5106 | ampdu_enable, rts_rate); |
---|
.. | .. |
---|
5157 | 5241 | } |
---|
5158 | 5242 | } |
---|
5159 | 5243 | |
---|
| 5244 | +/* |
---|
| 5245 | + * The RTL8723BU/RTL8192EU vendor driver use coexistence table type |
---|
| 5246 | + * 0-7 to represent writing different combinations of register values |
---|
| 5247 | + * to REG_BT_COEX_TABLEs. It's for different kinds of coexistence use |
---|
| 5248 | + * cases which Realtek doesn't provide detail for these settings. Keep |
---|
| 5249 | + * this aligned with vendor driver for easier maintenance. |
---|
| 5250 | + */ |
---|
| 5251 | +static |
---|
| 5252 | +void rtl8723bu_set_coex_with_type(struct rtl8xxxu_priv *priv, u8 type) |
---|
| 5253 | +{ |
---|
| 5254 | + switch (type) { |
---|
| 5255 | + case 0: |
---|
| 5256 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); |
---|
| 5257 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); |
---|
| 5258 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5259 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5260 | + break; |
---|
| 5261 | + case 1: |
---|
| 5262 | + case 3: |
---|
| 5263 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); |
---|
| 5264 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); |
---|
| 5265 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5266 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5267 | + break; |
---|
| 5268 | + case 2: |
---|
| 5269 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); |
---|
| 5270 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); |
---|
| 5271 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5272 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5273 | + break; |
---|
| 5274 | + case 4: |
---|
| 5275 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); |
---|
| 5276 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaa5a5a); |
---|
| 5277 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5278 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5279 | + break; |
---|
| 5280 | + case 5: |
---|
| 5281 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); |
---|
| 5282 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaa5a5a5a); |
---|
| 5283 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5284 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5285 | + break; |
---|
| 5286 | + case 6: |
---|
| 5287 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); |
---|
| 5288 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); |
---|
| 5289 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5290 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5291 | + break; |
---|
| 5292 | + case 7: |
---|
| 5293 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0xaaaaaaaa); |
---|
| 5294 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); |
---|
| 5295 | + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); |
---|
| 5296 | + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); |
---|
| 5297 | + break; |
---|
| 5298 | + default: |
---|
| 5299 | + break; |
---|
| 5300 | + } |
---|
| 5301 | +} |
---|
| 5302 | + |
---|
| 5303 | +static |
---|
| 5304 | +void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) |
---|
| 5305 | +{ |
---|
| 5306 | + struct rtl8xxxu_btcoex *btcoex = &priv->bt_coex; |
---|
| 5307 | + |
---|
| 5308 | + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) |
---|
| 5309 | + btcoex->c2h_bt_inquiry = true; |
---|
| 5310 | + else |
---|
| 5311 | + btcoex->c2h_bt_inquiry = false; |
---|
| 5312 | + |
---|
| 5313 | + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { |
---|
| 5314 | + btcoex->bt_status = BT_8723B_1ANT_STATUS_NON_CONNECTED_IDLE; |
---|
| 5315 | + btcoex->has_sco = false; |
---|
| 5316 | + btcoex->has_hid = false; |
---|
| 5317 | + btcoex->has_pan = false; |
---|
| 5318 | + btcoex->has_a2dp = false; |
---|
| 5319 | + } else { |
---|
| 5320 | + if ((bt_info & 0x1f) == BT_INFO_8723B_1ANT_B_CONNECTION) |
---|
| 5321 | + btcoex->bt_status = BT_8723B_1ANT_STATUS_CONNECTED_IDLE; |
---|
| 5322 | + else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || |
---|
| 5323 | + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) |
---|
| 5324 | + btcoex->bt_status = BT_8723B_1ANT_STATUS_SCO_BUSY; |
---|
| 5325 | + else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) |
---|
| 5326 | + btcoex->bt_status = BT_8723B_1ANT_STATUS_ACL_BUSY; |
---|
| 5327 | + else |
---|
| 5328 | + btcoex->bt_status = BT_8723B_1ANT_STATUS_MAX; |
---|
| 5329 | + |
---|
| 5330 | + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) |
---|
| 5331 | + btcoex->has_pan = true; |
---|
| 5332 | + else |
---|
| 5333 | + btcoex->has_pan = false; |
---|
| 5334 | + |
---|
| 5335 | + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) |
---|
| 5336 | + btcoex->has_a2dp = true; |
---|
| 5337 | + else |
---|
| 5338 | + btcoex->has_a2dp = false; |
---|
| 5339 | + |
---|
| 5340 | + if (bt_info & BT_INFO_8723B_1ANT_B_HID) |
---|
| 5341 | + btcoex->has_hid = true; |
---|
| 5342 | + else |
---|
| 5343 | + btcoex->has_hid = false; |
---|
| 5344 | + |
---|
| 5345 | + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) |
---|
| 5346 | + btcoex->has_sco = true; |
---|
| 5347 | + else |
---|
| 5348 | + btcoex->has_sco = false; |
---|
| 5349 | + } |
---|
| 5350 | + |
---|
| 5351 | + if (!btcoex->has_a2dp && !btcoex->has_sco && |
---|
| 5352 | + !btcoex->has_pan && btcoex->has_hid) |
---|
| 5353 | + btcoex->hid_only = true; |
---|
| 5354 | + else |
---|
| 5355 | + btcoex->hid_only = false; |
---|
| 5356 | + |
---|
| 5357 | + if (!btcoex->has_sco && !btcoex->has_pan && |
---|
| 5358 | + !btcoex->has_hid && btcoex->has_a2dp) |
---|
| 5359 | + btcoex->has_a2dp = true; |
---|
| 5360 | + else |
---|
| 5361 | + btcoex->has_a2dp = false; |
---|
| 5362 | + |
---|
| 5363 | + if (btcoex->bt_status == BT_8723B_1ANT_STATUS_SCO_BUSY || |
---|
| 5364 | + btcoex->bt_status == BT_8723B_1ANT_STATUS_ACL_BUSY) |
---|
| 5365 | + btcoex->bt_busy = true; |
---|
| 5366 | + else |
---|
| 5367 | + btcoex->bt_busy = false; |
---|
| 5368 | +} |
---|
| 5369 | + |
---|
| 5370 | +static |
---|
| 5371 | +void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) |
---|
| 5372 | +{ |
---|
| 5373 | + struct ieee80211_vif *vif; |
---|
| 5374 | + struct rtl8xxxu_btcoex *btcoex; |
---|
| 5375 | + bool wifi_connected; |
---|
| 5376 | + |
---|
| 5377 | + vif = priv->vif; |
---|
| 5378 | + btcoex = &priv->bt_coex; |
---|
| 5379 | + wifi_connected = (vif && vif->bss_conf.assoc); |
---|
| 5380 | + |
---|
| 5381 | + if (!wifi_connected) { |
---|
| 5382 | + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); |
---|
| 5383 | + rtl8723bu_set_coex_with_type(priv, 0); |
---|
| 5384 | + } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) { |
---|
| 5385 | + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11); |
---|
| 5386 | + rtl8723bu_set_coex_with_type(priv, 4); |
---|
| 5387 | + } else if (btcoex->has_pan) { |
---|
| 5388 | + rtl8723bu_set_ps_tdma(priv, 0x61, 0x3f, 0x3, 0x11, 0x11); |
---|
| 5389 | + rtl8723bu_set_coex_with_type(priv, 4); |
---|
| 5390 | + } else { |
---|
| 5391 | + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); |
---|
| 5392 | + rtl8723bu_set_coex_with_type(priv, 7); |
---|
| 5393 | + } |
---|
| 5394 | +} |
---|
| 5395 | + |
---|
| 5396 | +static |
---|
| 5397 | +void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) |
---|
| 5398 | +{ |
---|
| 5399 | + struct ieee80211_vif *vif; |
---|
| 5400 | + struct rtl8xxxu_btcoex *btcoex; |
---|
| 5401 | + bool wifi_connected; |
---|
| 5402 | + |
---|
| 5403 | + vif = priv->vif; |
---|
| 5404 | + btcoex = &priv->bt_coex; |
---|
| 5405 | + wifi_connected = (vif && vif->bss_conf.assoc); |
---|
| 5406 | + |
---|
| 5407 | + if (wifi_connected) { |
---|
| 5408 | + u32 val32 = 0; |
---|
| 5409 | + u32 high_prio_tx = 0, high_prio_rx = 0; |
---|
| 5410 | + |
---|
| 5411 | + val32 = rtl8xxxu_read32(priv, 0x770); |
---|
| 5412 | + high_prio_tx = val32 & 0x0000ffff; |
---|
| 5413 | + high_prio_rx = (val32 & 0xffff0000) >> 16; |
---|
| 5414 | + |
---|
| 5415 | + if (btcoex->bt_busy) { |
---|
| 5416 | + if (btcoex->hid_only) { |
---|
| 5417 | + rtl8723bu_set_ps_tdma(priv, 0x61, 0x20, |
---|
| 5418 | + 0x3, 0x11, 0x11); |
---|
| 5419 | + rtl8723bu_set_coex_with_type(priv, 5); |
---|
| 5420 | + } else if (btcoex->a2dp_only) { |
---|
| 5421 | + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, |
---|
| 5422 | + 0x3, 0x11, 0x11); |
---|
| 5423 | + rtl8723bu_set_coex_with_type(priv, 4); |
---|
| 5424 | + } else if ((btcoex->has_a2dp && btcoex->has_pan) || |
---|
| 5425 | + (btcoex->has_hid && btcoex->has_a2dp && |
---|
| 5426 | + btcoex->has_pan)) { |
---|
| 5427 | + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, |
---|
| 5428 | + 0x3, 0x10, 0x10); |
---|
| 5429 | + rtl8723bu_set_coex_with_type(priv, 4); |
---|
| 5430 | + } else if (btcoex->has_hid && btcoex->has_a2dp) { |
---|
| 5431 | + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, |
---|
| 5432 | + 0x3, 0x10, 0x10); |
---|
| 5433 | + rtl8723bu_set_coex_with_type(priv, 3); |
---|
| 5434 | + } else { |
---|
| 5435 | + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, |
---|
| 5436 | + 0x3, 0x11, 0x11); |
---|
| 5437 | + rtl8723bu_set_coex_with_type(priv, 4); |
---|
| 5438 | + } |
---|
| 5439 | + } else { |
---|
| 5440 | + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); |
---|
| 5441 | + if (high_prio_tx + high_prio_rx <= 60) |
---|
| 5442 | + rtl8723bu_set_coex_with_type(priv, 2); |
---|
| 5443 | + else |
---|
| 5444 | + rtl8723bu_set_coex_with_type(priv, 7); |
---|
| 5445 | + } |
---|
| 5446 | + } else { |
---|
| 5447 | + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); |
---|
| 5448 | + rtl8723bu_set_coex_with_type(priv, 0); |
---|
| 5449 | + } |
---|
| 5450 | +} |
---|
| 5451 | + |
---|
| 5452 | +static struct ieee80211_rate rtl8xxxu_legacy_ratetable[] = { |
---|
| 5453 | + {.bitrate = 10, .hw_value = 0x00,}, |
---|
| 5454 | + {.bitrate = 20, .hw_value = 0x01,}, |
---|
| 5455 | + {.bitrate = 55, .hw_value = 0x02,}, |
---|
| 5456 | + {.bitrate = 110, .hw_value = 0x03,}, |
---|
| 5457 | + {.bitrate = 60, .hw_value = 0x04,}, |
---|
| 5458 | + {.bitrate = 90, .hw_value = 0x05,}, |
---|
| 5459 | + {.bitrate = 120, .hw_value = 0x06,}, |
---|
| 5460 | + {.bitrate = 180, .hw_value = 0x07,}, |
---|
| 5461 | + {.bitrate = 240, .hw_value = 0x08,}, |
---|
| 5462 | + {.bitrate = 360, .hw_value = 0x09,}, |
---|
| 5463 | + {.bitrate = 480, .hw_value = 0x0a,}, |
---|
| 5464 | + {.bitrate = 540, .hw_value = 0x0b,}, |
---|
| 5465 | +}; |
---|
| 5466 | + |
---|
| 5467 | +static void rtl8xxxu_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) |
---|
| 5468 | +{ |
---|
| 5469 | + if (rate <= DESC_RATE_54M) |
---|
| 5470 | + return; |
---|
| 5471 | + |
---|
| 5472 | + if (rate >= DESC_RATE_MCS0 && rate <= DESC_RATE_MCS15) { |
---|
| 5473 | + if (rate < DESC_RATE_MCS8) |
---|
| 5474 | + *nss = 1; |
---|
| 5475 | + else |
---|
| 5476 | + *nss = 2; |
---|
| 5477 | + *mcs = rate - DESC_RATE_MCS0; |
---|
| 5478 | + } |
---|
| 5479 | +} |
---|
| 5480 | + |
---|
| 5481 | +static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) |
---|
| 5482 | +{ |
---|
| 5483 | + struct rtl8xxxu_priv *priv; |
---|
| 5484 | + struct rtl8723bu_c2h *c2h; |
---|
| 5485 | + struct sk_buff *skb = NULL; |
---|
| 5486 | + unsigned long flags; |
---|
| 5487 | + u8 bt_info = 0; |
---|
| 5488 | + struct rtl8xxxu_btcoex *btcoex; |
---|
| 5489 | + struct rtl8xxxu_ra_report *rarpt; |
---|
| 5490 | + u8 rate, sgi, bw; |
---|
| 5491 | + u32 bit_rate; |
---|
| 5492 | + u8 mcs = 0, nss = 0; |
---|
| 5493 | + |
---|
| 5494 | + priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); |
---|
| 5495 | + btcoex = &priv->bt_coex; |
---|
| 5496 | + rarpt = &priv->ra_report; |
---|
| 5497 | + |
---|
| 5498 | + if (priv->rf_paths > 1) |
---|
| 5499 | + goto out; |
---|
| 5500 | + |
---|
| 5501 | + while (!skb_queue_empty(&priv->c2hcmd_queue)) { |
---|
| 5502 | + spin_lock_irqsave(&priv->c2hcmd_lock, flags); |
---|
| 5503 | + skb = __skb_dequeue(&priv->c2hcmd_queue); |
---|
| 5504 | + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); |
---|
| 5505 | + |
---|
| 5506 | + c2h = (struct rtl8723bu_c2h *)skb->data; |
---|
| 5507 | + |
---|
| 5508 | + switch (c2h->id) { |
---|
| 5509 | + case C2H_8723B_BT_INFO: |
---|
| 5510 | + bt_info = c2h->bt_info.bt_info; |
---|
| 5511 | + |
---|
| 5512 | + rtl8723bu_update_bt_link_info(priv, bt_info); |
---|
| 5513 | + if (btcoex->c2h_bt_inquiry) { |
---|
| 5514 | + rtl8723bu_handle_bt_inquiry(priv); |
---|
| 5515 | + break; |
---|
| 5516 | + } |
---|
| 5517 | + rtl8723bu_handle_bt_info(priv); |
---|
| 5518 | + break; |
---|
| 5519 | + case C2H_8723B_RA_REPORT: |
---|
| 5520 | + rarpt->txrate.flags = 0; |
---|
| 5521 | + rate = c2h->ra_report.rate; |
---|
| 5522 | + sgi = c2h->ra_report.sgi; |
---|
| 5523 | + bw = c2h->ra_report.bw; |
---|
| 5524 | + |
---|
| 5525 | + if (rate < DESC_RATE_MCS0) { |
---|
| 5526 | + rarpt->txrate.legacy = |
---|
| 5527 | + rtl8xxxu_legacy_ratetable[rate].bitrate; |
---|
| 5528 | + } else { |
---|
| 5529 | + rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss); |
---|
| 5530 | + rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS; |
---|
| 5531 | + |
---|
| 5532 | + rarpt->txrate.mcs = mcs; |
---|
| 5533 | + rarpt->txrate.nss = nss; |
---|
| 5534 | + |
---|
| 5535 | + if (sgi) { |
---|
| 5536 | + rarpt->txrate.flags |= |
---|
| 5537 | + RATE_INFO_FLAGS_SHORT_GI; |
---|
| 5538 | + } |
---|
| 5539 | + |
---|
| 5540 | + if (bw == RATE_INFO_BW_20) |
---|
| 5541 | + rarpt->txrate.bw |= RATE_INFO_BW_20; |
---|
| 5542 | + } |
---|
| 5543 | + bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate); |
---|
| 5544 | + rarpt->bit_rate = bit_rate; |
---|
| 5545 | + rarpt->desc_rate = rate; |
---|
| 5546 | + break; |
---|
| 5547 | + default: |
---|
| 5548 | + break; |
---|
| 5549 | + } |
---|
| 5550 | + } |
---|
| 5551 | + |
---|
| 5552 | +out: |
---|
| 5553 | + dev_kfree_skb(skb); |
---|
| 5554 | +} |
---|
| 5555 | + |
---|
5160 | 5556 | static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, |
---|
5161 | 5557 | struct sk_buff *skb) |
---|
5162 | 5558 | { |
---|
5163 | 5559 | struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; |
---|
5164 | 5560 | struct device *dev = &priv->udev->dev; |
---|
5165 | 5561 | int len; |
---|
| 5562 | + unsigned long flags; |
---|
5166 | 5563 | |
---|
5167 | 5564 | len = skb->len - 2; |
---|
5168 | 5565 | |
---|
.. | .. |
---|
5190 | 5587 | case C2H_8723B_RA_REPORT: |
---|
5191 | 5588 | dev_dbg(dev, |
---|
5192 | 5589 | "C2H RA RPT: rate %02x, unk %i, macid %02x, noise %i\n", |
---|
5193 | | - c2h->ra_report.rate, c2h->ra_report.dummy0_0, |
---|
| 5590 | + c2h->ra_report.rate, c2h->ra_report.sgi, |
---|
5194 | 5591 | c2h->ra_report.macid, c2h->ra_report.noisy_state); |
---|
5195 | 5592 | break; |
---|
5196 | 5593 | default: |
---|
.. | .. |
---|
5200 | 5597 | 16, 1, c2h->raw.payload, len, false); |
---|
5201 | 5598 | break; |
---|
5202 | 5599 | } |
---|
| 5600 | + |
---|
| 5601 | + spin_lock_irqsave(&priv->c2hcmd_lock, flags); |
---|
| 5602 | + __skb_queue_tail(&priv->c2hcmd_queue, skb); |
---|
| 5603 | + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); |
---|
| 5604 | + |
---|
| 5605 | + schedule_work(&priv->c2hcmd_work); |
---|
5203 | 5606 | } |
---|
5204 | 5607 | |
---|
5205 | 5608 | int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) |
---|
.. | .. |
---|
5324 | 5727 | struct device *dev = &priv->udev->dev; |
---|
5325 | 5728 | dev_dbg(dev, "%s: C2H packet\n", __func__); |
---|
5326 | 5729 | rtl8723bu_handle_c2h(priv, skb); |
---|
5327 | | - dev_kfree_skb(skb); |
---|
5328 | 5730 | return RX_TYPE_C2H; |
---|
5329 | 5731 | } |
---|
5330 | 5732 | |
---|
.. | .. |
---|
5474 | 5876 | |
---|
5475 | 5877 | switch (vif->type) { |
---|
5476 | 5878 | case NL80211_IFTYPE_STATION: |
---|
| 5879 | + if (!priv->vif) |
---|
| 5880 | + priv->vif = vif; |
---|
| 5881 | + else |
---|
| 5882 | + return -EOPNOTSUPP; |
---|
5477 | 5883 | rtl8xxxu_stop_tx_beacon(priv); |
---|
5478 | 5884 | |
---|
5479 | 5885 | val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); |
---|
.. | .. |
---|
5497 | 5903 | struct rtl8xxxu_priv *priv = hw->priv; |
---|
5498 | 5904 | |
---|
5499 | 5905 | dev_dbg(&priv->udev->dev, "%s\n", __func__); |
---|
| 5906 | + |
---|
| 5907 | + if (priv->vif) |
---|
| 5908 | + priv->vif = NULL; |
---|
5500 | 5909 | } |
---|
5501 | 5910 | |
---|
5502 | 5911 | static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) |
---|
.. | .. |
---|
5746 | 6155 | struct device *dev = &priv->udev->dev; |
---|
5747 | 6156 | u8 ampdu_factor, ampdu_density; |
---|
5748 | 6157 | struct ieee80211_sta *sta = params->sta; |
---|
| 6158 | + u16 tid = params->tid; |
---|
5749 | 6159 | enum ieee80211_ampdu_mlme_action action = params->action; |
---|
5750 | 6160 | |
---|
5751 | 6161 | switch (action) { |
---|
.. | .. |
---|
5758 | 6168 | dev_dbg(dev, |
---|
5759 | 6169 | "Changed HT: ampdu_factor %02x, ampdu_density %02x\n", |
---|
5760 | 6170 | ampdu_factor, ampdu_density); |
---|
5761 | | - break; |
---|
| 6171 | + return IEEE80211_AMPDU_TX_START_IMMEDIATE; |
---|
| 6172 | + case IEEE80211_AMPDU_TX_STOP_CONT: |
---|
5762 | 6173 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
---|
5763 | | - dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__); |
---|
5764 | | - rtl8xxxu_set_ampdu_factor(priv, 0); |
---|
5765 | | - rtl8xxxu_set_ampdu_min_space(priv, 0); |
---|
5766 | | - break; |
---|
5767 | 6174 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
---|
5768 | | - dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n", |
---|
5769 | | - __func__); |
---|
| 6175 | + dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP\n", __func__); |
---|
5770 | 6176 | rtl8xxxu_set_ampdu_factor(priv, 0); |
---|
5771 | 6177 | rtl8xxxu_set_ampdu_min_space(priv, 0); |
---|
| 6178 | + clear_bit(tid, priv->tx_aggr_started); |
---|
| 6179 | + clear_bit(tid, priv->tid_tx_operational); |
---|
| 6180 | + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
---|
| 6181 | + break; |
---|
| 6182 | + case IEEE80211_AMPDU_TX_OPERATIONAL: |
---|
| 6183 | + dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_OPERATIONAL\n", __func__); |
---|
| 6184 | + set_bit(tid, priv->tid_tx_operational); |
---|
5772 | 6185 | break; |
---|
5773 | 6186 | case IEEE80211_AMPDU_RX_START: |
---|
5774 | 6187 | dev_dbg(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__); |
---|
.. | .. |
---|
5780 | 6193 | break; |
---|
5781 | 6194 | } |
---|
5782 | 6195 | return 0; |
---|
| 6196 | +} |
---|
| 6197 | + |
---|
| 6198 | +static void |
---|
| 6199 | +rtl8xxxu_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
---|
| 6200 | + struct ieee80211_sta *sta, struct station_info *sinfo) |
---|
| 6201 | +{ |
---|
| 6202 | + struct rtl8xxxu_priv *priv = hw->priv; |
---|
| 6203 | + |
---|
| 6204 | + sinfo->txrate = priv->ra_report.txrate; |
---|
| 6205 | + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); |
---|
| 6206 | +} |
---|
| 6207 | + |
---|
| 6208 | +static u8 rtl8xxxu_signal_to_snr(int signal) |
---|
| 6209 | +{ |
---|
| 6210 | + if (signal < RTL8XXXU_NOISE_FLOOR_MIN) |
---|
| 6211 | + signal = RTL8XXXU_NOISE_FLOOR_MIN; |
---|
| 6212 | + else if (signal > 0) |
---|
| 6213 | + signal = 0; |
---|
| 6214 | + return (u8)(signal - RTL8XXXU_NOISE_FLOOR_MIN); |
---|
| 6215 | +} |
---|
| 6216 | + |
---|
| 6217 | +static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, |
---|
| 6218 | + int signal, struct ieee80211_sta *sta) |
---|
| 6219 | +{ |
---|
| 6220 | + struct ieee80211_hw *hw = priv->hw; |
---|
| 6221 | + u16 wireless_mode; |
---|
| 6222 | + u8 rssi_level, ratr_idx; |
---|
| 6223 | + u8 txbw_40mhz; |
---|
| 6224 | + u8 snr, snr_thresh_high, snr_thresh_low; |
---|
| 6225 | + u8 go_up_gap = 5; |
---|
| 6226 | + |
---|
| 6227 | + rssi_level = priv->rssi_level; |
---|
| 6228 | + snr = rtl8xxxu_signal_to_snr(signal); |
---|
| 6229 | + snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH; |
---|
| 6230 | + snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW; |
---|
| 6231 | + txbw_40mhz = (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) ? 1 : 0; |
---|
| 6232 | + |
---|
| 6233 | + switch (rssi_level) { |
---|
| 6234 | + case RTL8XXXU_RATR_STA_MID: |
---|
| 6235 | + snr_thresh_high += go_up_gap; |
---|
| 6236 | + break; |
---|
| 6237 | + case RTL8XXXU_RATR_STA_LOW: |
---|
| 6238 | + snr_thresh_high += go_up_gap; |
---|
| 6239 | + snr_thresh_low += go_up_gap; |
---|
| 6240 | + break; |
---|
| 6241 | + default: |
---|
| 6242 | + break; |
---|
| 6243 | + } |
---|
| 6244 | + |
---|
| 6245 | + if (snr > snr_thresh_high) |
---|
| 6246 | + rssi_level = RTL8XXXU_RATR_STA_HIGH; |
---|
| 6247 | + else if (snr > snr_thresh_low) |
---|
| 6248 | + rssi_level = RTL8XXXU_RATR_STA_MID; |
---|
| 6249 | + else |
---|
| 6250 | + rssi_level = RTL8XXXU_RATR_STA_LOW; |
---|
| 6251 | + |
---|
| 6252 | + if (rssi_level != priv->rssi_level) { |
---|
| 6253 | + int sgi = 0; |
---|
| 6254 | + u32 rate_bitmap = 0; |
---|
| 6255 | + |
---|
| 6256 | + rcu_read_lock(); |
---|
| 6257 | + rate_bitmap = (sta->supp_rates[0] & 0xfff) | |
---|
| 6258 | + (sta->ht_cap.mcs.rx_mask[0] << 12) | |
---|
| 6259 | + (sta->ht_cap.mcs.rx_mask[1] << 20); |
---|
| 6260 | + if (sta->ht_cap.cap & |
---|
| 6261 | + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) |
---|
| 6262 | + sgi = 1; |
---|
| 6263 | + rcu_read_unlock(); |
---|
| 6264 | + |
---|
| 6265 | + wireless_mode = rtl8xxxu_wireless_mode(hw, sta); |
---|
| 6266 | + switch (wireless_mode) { |
---|
| 6267 | + case WIRELESS_MODE_B: |
---|
| 6268 | + ratr_idx = RATEID_IDX_B; |
---|
| 6269 | + if (rate_bitmap & 0x0000000c) |
---|
| 6270 | + rate_bitmap &= 0x0000000d; |
---|
| 6271 | + else |
---|
| 6272 | + rate_bitmap &= 0x0000000f; |
---|
| 6273 | + break; |
---|
| 6274 | + case WIRELESS_MODE_A: |
---|
| 6275 | + case WIRELESS_MODE_G: |
---|
| 6276 | + ratr_idx = RATEID_IDX_G; |
---|
| 6277 | + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) |
---|
| 6278 | + rate_bitmap &= 0x00000f00; |
---|
| 6279 | + else |
---|
| 6280 | + rate_bitmap &= 0x00000ff0; |
---|
| 6281 | + break; |
---|
| 6282 | + case (WIRELESS_MODE_B | WIRELESS_MODE_G): |
---|
| 6283 | + ratr_idx = RATEID_IDX_BG; |
---|
| 6284 | + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) |
---|
| 6285 | + rate_bitmap &= 0x00000f00; |
---|
| 6286 | + else if (rssi_level == RTL8XXXU_RATR_STA_MID) |
---|
| 6287 | + rate_bitmap &= 0x00000ff0; |
---|
| 6288 | + else |
---|
| 6289 | + rate_bitmap &= 0x00000ff5; |
---|
| 6290 | + break; |
---|
| 6291 | + case WIRELESS_MODE_N_24G: |
---|
| 6292 | + case WIRELESS_MODE_N_5G: |
---|
| 6293 | + case (WIRELESS_MODE_G | WIRELESS_MODE_N_24G): |
---|
| 6294 | + case (WIRELESS_MODE_A | WIRELESS_MODE_N_5G): |
---|
| 6295 | + if (priv->tx_paths == 2 && priv->rx_paths == 2) |
---|
| 6296 | + ratr_idx = RATEID_IDX_GN_N2SS; |
---|
| 6297 | + else |
---|
| 6298 | + ratr_idx = RATEID_IDX_GN_N1SS; |
---|
| 6299 | + break; |
---|
| 6300 | + case (WIRELESS_MODE_B | WIRELESS_MODE_G | WIRELESS_MODE_N_24G): |
---|
| 6301 | + case (WIRELESS_MODE_B | WIRELESS_MODE_N_24G): |
---|
| 6302 | + if (txbw_40mhz) { |
---|
| 6303 | + if (priv->tx_paths == 2 && priv->rx_paths == 2) |
---|
| 6304 | + ratr_idx = RATEID_IDX_BGN_40M_2SS; |
---|
| 6305 | + else |
---|
| 6306 | + ratr_idx = RATEID_IDX_BGN_40M_1SS; |
---|
| 6307 | + } else { |
---|
| 6308 | + if (priv->tx_paths == 2 && priv->rx_paths == 2) |
---|
| 6309 | + ratr_idx = RATEID_IDX_BGN_20M_2SS_BN; |
---|
| 6310 | + else |
---|
| 6311 | + ratr_idx = RATEID_IDX_BGN_20M_1SS_BN; |
---|
| 6312 | + } |
---|
| 6313 | + |
---|
| 6314 | + if (priv->tx_paths == 2 && priv->rx_paths == 2) { |
---|
| 6315 | + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { |
---|
| 6316 | + rate_bitmap &= 0x0f8f0000; |
---|
| 6317 | + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { |
---|
| 6318 | + rate_bitmap &= 0x0f8ff000; |
---|
| 6319 | + } else { |
---|
| 6320 | + if (txbw_40mhz) |
---|
| 6321 | + rate_bitmap &= 0x0f8ff015; |
---|
| 6322 | + else |
---|
| 6323 | + rate_bitmap &= 0x0f8ff005; |
---|
| 6324 | + } |
---|
| 6325 | + } else { |
---|
| 6326 | + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { |
---|
| 6327 | + rate_bitmap &= 0x000f0000; |
---|
| 6328 | + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { |
---|
| 6329 | + rate_bitmap &= 0x000ff000; |
---|
| 6330 | + } else { |
---|
| 6331 | + if (txbw_40mhz) |
---|
| 6332 | + rate_bitmap &= 0x000ff015; |
---|
| 6333 | + else |
---|
| 6334 | + rate_bitmap &= 0x000ff005; |
---|
| 6335 | + } |
---|
| 6336 | + } |
---|
| 6337 | + break; |
---|
| 6338 | + default: |
---|
| 6339 | + ratr_idx = RATEID_IDX_BGN_40M_2SS; |
---|
| 6340 | + rate_bitmap &= 0x0fffffff; |
---|
| 6341 | + break; |
---|
| 6342 | + } |
---|
| 6343 | + |
---|
| 6344 | + priv->rssi_level = rssi_level; |
---|
| 6345 | + priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi); |
---|
| 6346 | + } |
---|
| 6347 | +} |
---|
| 6348 | + |
---|
| 6349 | +static void rtl8xxxu_watchdog_callback(struct work_struct *work) |
---|
| 6350 | +{ |
---|
| 6351 | + struct ieee80211_vif *vif; |
---|
| 6352 | + struct rtl8xxxu_priv *priv; |
---|
| 6353 | + |
---|
| 6354 | + priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); |
---|
| 6355 | + vif = priv->vif; |
---|
| 6356 | + |
---|
| 6357 | + if (vif && vif->type == NL80211_IFTYPE_STATION) { |
---|
| 6358 | + int signal; |
---|
| 6359 | + struct ieee80211_sta *sta; |
---|
| 6360 | + |
---|
| 6361 | + rcu_read_lock(); |
---|
| 6362 | + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); |
---|
| 6363 | + if (!sta) { |
---|
| 6364 | + struct device *dev = &priv->udev->dev; |
---|
| 6365 | + |
---|
| 6366 | + dev_dbg(dev, "%s: no sta found\n", __func__); |
---|
| 6367 | + rcu_read_unlock(); |
---|
| 6368 | + goto out; |
---|
| 6369 | + } |
---|
| 6370 | + rcu_read_unlock(); |
---|
| 6371 | + |
---|
| 6372 | + signal = ieee80211_ave_rssi(vif); |
---|
| 6373 | + rtl8xxxu_refresh_rate_mask(priv, signal, sta); |
---|
| 6374 | + } |
---|
| 6375 | + |
---|
| 6376 | +out: |
---|
| 6377 | + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); |
---|
5783 | 6378 | } |
---|
5784 | 6379 | |
---|
5785 | 6380 | static int rtl8xxxu_start(struct ieee80211_hw *hw) |
---|
.. | .. |
---|
5846 | 6441 | rtl8xxxu_queue_rx_urb(priv, rx_urb); |
---|
5847 | 6442 | } |
---|
5848 | 6443 | } |
---|
| 6444 | + |
---|
| 6445 | + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); |
---|
5849 | 6446 | exit: |
---|
5850 | 6447 | /* |
---|
5851 | 6448 | * Accept all data and mgmt frames |
---|
.. | .. |
---|
5897 | 6494 | if (priv->usb_interrupts) |
---|
5898 | 6495 | rtl8xxxu_write32(priv, REG_USB_HIMR, 0); |
---|
5899 | 6496 | |
---|
| 6497 | + cancel_delayed_work_sync(&priv->ra_watchdog); |
---|
| 6498 | + |
---|
5900 | 6499 | rtl8xxxu_free_rx_resources(priv); |
---|
5901 | 6500 | rtl8xxxu_free_tx_resources(priv); |
---|
5902 | 6501 | } |
---|
.. | .. |
---|
5916 | 6515 | .sw_scan_complete = rtl8xxxu_sw_scan_complete, |
---|
5917 | 6516 | .set_key = rtl8xxxu_set_key, |
---|
5918 | 6517 | .ampdu_action = rtl8xxxu_ampdu_action, |
---|
| 6518 | + .sta_statistics = rtl8xxxu_sta_statistics, |
---|
5919 | 6519 | }; |
---|
5920 | 6520 | |
---|
5921 | 6521 | static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, |
---|
.. | .. |
---|
6019 | 6619 | } |
---|
6020 | 6620 | break; |
---|
6021 | 6621 | case 0x7392: |
---|
6022 | | - if (id->idProduct == 0x7811) |
---|
| 6622 | + if (id->idProduct == 0x7811 || id->idProduct == 0xa611) |
---|
6023 | 6623 | untested = 0; |
---|
6024 | 6624 | break; |
---|
6025 | 6625 | case 0x050d: |
---|
.. | .. |
---|
6069 | 6669 | INIT_LIST_HEAD(&priv->rx_urb_pending_list); |
---|
6070 | 6670 | spin_lock_init(&priv->rx_urb_lock); |
---|
6071 | 6671 | INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); |
---|
| 6672 | + INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); |
---|
| 6673 | + spin_lock_init(&priv->c2hcmd_lock); |
---|
| 6674 | + INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); |
---|
| 6675 | + skb_queue_head_init(&priv->c2hcmd_queue); |
---|
6072 | 6676 | |
---|
6073 | 6677 | usb_set_intfdata(interface, hw); |
---|
6074 | 6678 | |
---|
.. | .. |
---|
6223 | 6827 | .driver_info = (unsigned long)&rtl8192eu_fops}, |
---|
6224 | 6828 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xb720, 0xff, 0xff, 0xff), |
---|
6225 | 6829 | .driver_info = (unsigned long)&rtl8723bu_fops}, |
---|
| 6830 | +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa611, 0xff, 0xff, 0xff), |
---|
| 6831 | + .driver_info = (unsigned long)&rtl8723bu_fops}, |
---|
6226 | 6832 | #ifdef CONFIG_RTL8XXXU_UNTESTED |
---|
6227 | 6833 | /* Still supported by rtlwifi */ |
---|
6228 | 6834 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), |
---|
.. | .. |
---|
6244 | 6850 | {USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff), |
---|
6245 | 6851 | .driver_info = (unsigned long)&rtl8192cu_fops}, |
---|
6246 | 6852 | /* Currently untested 8188 series devices */ |
---|
| 6853 | +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x018a, 0xff, 0xff, 0xff), |
---|
| 6854 | + .driver_info = (unsigned long)&rtl8192cu_fops}, |
---|
6247 | 6855 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff), |
---|
6248 | 6856 | .driver_info = (unsigned long)&rtl8192cu_fops}, |
---|
6249 | 6857 | {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff), |
---|