ath9k: Handle channel initialization for AP mode
authorSujith <Sujith.Manoharan@atheros.com>
Thu, 27 Nov 2008 04:16:27 +0000 (09:46 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 5 Dec 2008 14:32:59 +0000 (09:32 -0500)
Hostapd now passes the HT parameters through the config()
callback, use these to set the appropriate channel in AP mode.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/rc.c

index 437e38a..e05eb1f 100644 (file)
@@ -622,35 +622,35 @@ static int ath_get_channel(struct ath_softc *sc,
        return -1;
 }
 
+/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
+
 static u32 ath_get_extchanmode(struct ath_softc *sc,
                               struct ieee80211_channel *chan,
-                              struct ieee80211_bss_conf *bss_conf)
+                              int ext_chan_offset,
+                              enum ath9k_ht_macmode tx_chan_width)
 {
        u32 chanmode = 0;
-       u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset;
-       enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ?
-               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
 
        switch (chan->band) {
        case IEEE80211_BAND_2GHZ:
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+               if ((ext_chan_offset == 0) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_20))
                        chanmode = CHANNEL_G_HT20;
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+               if ((ext_chan_offset == 1) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_2040))
                        chanmode = CHANNEL_G_HT40PLUS;
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+               if ((ext_chan_offset == -1) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_2040))
                        chanmode = CHANNEL_G_HT40MINUS;
                break;
        case IEEE80211_BAND_5GHZ:
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
+               if ((ext_chan_offset == 0) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_20))
                        chanmode = CHANNEL_A_HT20;
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
+               if ((ext_chan_offset == 1) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_2040))
                        chanmode = CHANNEL_A_HT40PLUS;
-               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
+               if ((ext_chan_offset == -1) &&
                    (tx_chan_width == ATH9K_HT_MACMODE_2040))
                        chanmode = CHANNEL_A_HT40MINUS;
                break;
@@ -841,6 +841,18 @@ static void ath9k_ht_conf(struct ath_softc *sc,
        }
 }
 
+static inline int ath_sec_offset(u8 ext_offset)
+{
+       if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
+               return 0;
+       else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
+               return 1;
+       else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
+               return -1;
+
+       return 0;
+}
+
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
@@ -892,13 +904,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                }
 
                if (hw->conf.ht.enabled) {
-                       sc->sc_ah->ah_channels[pos].chanmode =
-                               ath_get_extchanmode(sc, curchan, bss_conf);
+                       int offset =
+                               ath_sec_offset(bss_conf->ht.secondary_channel_offset);
+                       sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
+                               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
 
-                       if (bss_conf->ht.width_40_ok)
-                               sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
-                       else
-                               sc->tx_chan_width = ATH9K_HT_MACMODE_20;
+                       sc->sc_ah->ah_channels[pos].chanmode =
+                               ath_get_extchanmode(sc, curchan,
+                                                   offset, sc->tx_chan_width);
                } else {
                        sc->sc_ah->ah_channels[pos].chanmode =
                                (curchan->band == IEEE80211_BAND_2GHZ) ?
@@ -2171,9 +2184,22 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                        (curchan->band == IEEE80211_BAND_2GHZ) ?
                        CHANNEL_G : CHANNEL_A;
 
-               if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+               if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) &&
+                   (conf->ht.enabled)) {
+                       sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
+                               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
+
+                       sc->sc_ah->ah_channels[pos].chanmode =
+                               ath_get_extchanmode(sc, curchan,
+                                                   conf->ht.sec_chan_offset,
+                                                   sc->tx_chan_width);
+               }
+
+               if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "%s: Unable to set channel\n", __func__);
+                       return -EINVAL;
+               }
        }
 
        if (changed & IEEE80211_CONF_CHANGE_HT)
index 93dfea8..7c08583 100644 (file)
@@ -1304,6 +1304,38 @@ static void ath_rc_tx_status(struct ath_softc *sc,
                         xretries, long_retry);
 }
 
+static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
+                                                   enum ieee80211_band band,
+                                                   bool is_ht, bool is_cw_40)
+{
+       int mode = 0;
+
+       switch(band) {
+       case IEEE80211_BAND_2GHZ:
+               mode = ATH9K_MODE_11G;
+               if (is_ht)
+                       mode = ATH9K_MODE_11NG_HT20;
+               if (is_cw_40)
+                       mode = ATH9K_MODE_11NG_HT40PLUS;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               mode = ATH9K_MODE_11A;
+               if (is_ht)
+                       mode = ATH9K_MODE_11NA_HT20;
+               if (is_cw_40)
+                       mode = ATH9K_MODE_11NA_HT40PLUS;
+               break;
+       default:
+               DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n");
+               return NULL;
+       }
+
+       BUG_ON(mode >= ATH9K_MODE_MAX);
+
+       DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode);
+       return sc->hw_rate_table[mode];
+}
+
 static void ath_rc_init(struct ath_softc *sc,
                        struct ath_rate_priv *ath_rc_priv,
                        struct ieee80211_supported_band *sband,
@@ -1314,16 +1346,25 @@ static void ath_rc_init(struct ath_softc *sc,
        u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
        u8 i, j, k, hi = 0, hthi = 0;
 
-       rate_table = sc->hw_rate_table[sc->sc_curmode];
+       /* FIXME: Adhoc */
+       if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
+           (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) {
+               bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               rate_table = ath_choose_rate_table(sc, sband->band,
+                                                  sta->ht_cap.ht_supported,
+                                                  is_cw_40);
+       } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+               /* sc_curmode would be set on init through config() */
+               rate_table = sc->hw_rate_table[sc->sc_curmode];
+       }
 
-       if (sta->ht_cap.ht_supported) {
-               if (sband->band == IEEE80211_BAND_2GHZ)
-                       rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
-               else
-                       rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
+       if (!rate_table) {
+               DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+               return;
+       }
 
+       if (sta->ht_cap.ht_supported) {
                ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
-
                if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
                        ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
        }