CHROMIUM: ath: Add ATH_DEFER_EEPROM_REGULATORY option
[cascardo/linux.git] / drivers / net / wireless / ath / regd.c
index 65ecb5b..575b80e 100644 (file)
@@ -21,6 +21,8 @@
 #include "regd.h"
 #include "regd_common.h"
 
+static int __ath_regd_init(struct ath_regulatory *reg);
+
 /*
  * This is a set of common rules used by our world regulatory domains.
  * We have 12 world regulatory domains. To save space we consolidate
@@ -127,6 +129,7 @@ bool ath_is_world_regd(struct ath_regulatory *reg)
 }
 EXPORT_SYMBOL(ath_is_world_regd);
 
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
 static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
 {
        /* this is the most restrictive */
@@ -159,6 +162,7 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
                return ath_default_world_regdomain();
        }
 }
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
 
 bool ath_is_49ghz_allowed(u16 regdomain)
 {
@@ -167,11 +171,13 @@ bool ath_is_49ghz_allowed(u16 regdomain)
 }
 EXPORT_SYMBOL(ath_is_49ghz_allowed);
 
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
 /* Frequency is one where radar detection is required */
 static bool ath_is_radar_freq(u16 center_freq)
 {
        return (center_freq >= 5260 && center_freq <= 5700);
 }
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
 
 /*
  * N.B: These exception rules do not apply radar freqs.
@@ -186,6 +192,7 @@ static void
 ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
                              enum nl80211_reg_initiator initiator)
 {
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
        enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
        const struct ieee80211_reg_rule *reg_rule;
@@ -239,6 +246,7 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
                        }
                }
        }
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
 
 }
 
@@ -247,6 +255,7 @@ static void
 ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
                                enum nl80211_reg_initiator initiator)
 {
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
        const struct ieee80211_reg_rule *reg_rule;
@@ -293,11 +302,13 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
                        if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                                ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
        }
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
 }
 
 /* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
 static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
 {
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
        unsigned int i;
@@ -326,6 +337,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
                                     IEEE80211_CHAN_NO_IBSS |
                                     IEEE80211_CHAN_PASSIVE_SCAN;
        }
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
 }
 
 static void ath_reg_apply_world_flags(struct wiphy *wiphy,
@@ -347,10 +359,26 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
        }
 }
 
+static u16 ath_regd_find_country_by_name(char *alpha2)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+               if (!memcmp(allCountries[i].isoName, alpha2, 2))
+                       return allCountries[i].countryCode;
+       }
+
+       return -1;
+}
+
 int ath_reg_notifier_apply(struct wiphy *wiphy,
                           struct regulatory_request *request,
                           struct ath_regulatory *reg)
 {
+       struct ath_common *common = container_of(reg, struct ath_common,
+                                                regulatory);
+       u16 country_code;
+
        /* We always apply this */
        ath_reg_apply_radar_flags(wiphy);
 
@@ -363,14 +391,37 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
                return 0;
 
        switch (request->initiator) {
-       case NL80211_REGDOM_SET_BY_DRIVER:
        case NL80211_REGDOM_SET_BY_CORE:
+               /*
+                * If common->reg_world_copy is world roaming it means we *were*
+                * world roaming... so we now have to restore that data.
+                */
+               if (!ath_is_world_regd(&common->reg_world_copy))
+                       break;
+
+               memcpy(reg, &common->reg_world_copy,
+                      sizeof(struct ath_regulatory));
+               break;
+       case NL80211_REGDOM_SET_BY_DRIVER:
        case NL80211_REGDOM_SET_BY_USER:
                break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-               if (ath_is_world_regd(reg))
-                       ath_reg_apply_world_flags(wiphy, request->initiator,
-                                                 reg);
+               if (!ath_is_world_regd(reg))
+                       break;
+
+               country_code = ath_regd_find_country_by_name(request->alpha2);
+               if (country_code == (u16) -1)
+                       break;
+
+               reg->current_rd = COUNTRY_ERD_FLAG;
+               reg->current_rd |= country_code;
+
+               printk(KERN_DEBUG "ath: regdomain 0x%0x updated by CountryIE\n",
+                       reg->current_rd);
+               __ath_regd_init(reg);
+
+               ath_reg_apply_world_flags(wiphy, request->initiator, reg);
+
                break;
        }
 
@@ -467,6 +518,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
                    int (*reg_notifier)(struct wiphy *wiphy,
                                        struct regulatory_request *request))
 {
+#ifndef CONFIG_ATH_DEFER_EEPROM_REGULATORY
        const struct ieee80211_regdomain *regd;
 
        wiphy->reg_notifier = reg_notifier;
@@ -490,6 +542,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
        wiphy_apply_custom_regulatory(wiphy, regd);
        ath_reg_apply_radar_flags(wiphy);
        ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+#endif  /* CONFIG_ATH_DEFER_EEPROM_REGULATORY */
        return 0;
 }
 
@@ -508,11 +561,7 @@ static void ath_regd_sanitize(struct ath_regulatory *reg)
        reg->current_rd = 0x64;
 }
 
-int
-ath_regd_init(struct ath_regulatory *reg,
-             struct wiphy *wiphy,
-             int (*reg_notifier)(struct wiphy *wiphy,
-                                 struct regulatory_request *request))
+static int __ath_regd_init(struct ath_regulatory *reg)
 {
        struct country_code_to_enum_rd *country = NULL;
        u16 regdmn;
@@ -583,7 +632,29 @@ ath_regd_init(struct ath_regulatory *reg,
        printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
                reg->regpair->regDmnEnum);
 
+       return 0;
+}
+
+int
+ath_regd_init(struct ath_regulatory *reg,
+             struct wiphy *wiphy,
+             int (*reg_notifier)(struct wiphy *wiphy,
+                                 struct regulatory_request *request))
+{
+       struct ath_common *common = container_of(reg, struct ath_common,
+                                                regulatory);
+       int r;
+
+       r = __ath_regd_init(reg);
+       if (r)
+               return r;
+
+       if (ath_is_world_regd(reg))
+               memcpy(&common->reg_world_copy, reg,
+                      sizeof(struct ath_regulatory));
+
        ath_regd_init_wiphy(reg, wiphy, reg_notifier);
+
        return 0;
 }
 EXPORT_SYMBOL(ath_regd_init);