rtlwifi: initialize local array and set value.
[pandora-kernel.git] / drivers / net / wireless / rtlwifi / regd.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29
30 #include "wifi.h"
31 #include "regd.h"
32
33 static struct country_code_to_enum_rd allCountries[] = {
34         {COUNTRY_CODE_FCC, "US"},
35         {COUNTRY_CODE_IC, "US"},
36         {COUNTRY_CODE_ETSI, "EC"},
37         {COUNTRY_CODE_SPAIN, "EC"},
38         {COUNTRY_CODE_FRANCE, "EC"},
39         {COUNTRY_CODE_MKK, "JP"},
40         {COUNTRY_CODE_MKK1, "JP"},
41         {COUNTRY_CODE_ISRAEL, "EC"},
42         {COUNTRY_CODE_TELEC, "JP"},
43         {COUNTRY_CODE_MIC, "JP"},
44         {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
45         {COUNTRY_CODE_WORLD_WIDE_13, "EC"},
46         {COUNTRY_CODE_TELEC_NETGEAR, "EC"},
47         {COUNTRY_CODE_WORLD_WIDE_13_5G_ALL, "US"},
48 };
49
50 /*
51  *Only these channels all allow active
52  *scan on all world regulatory domains
53  */
54 #define RTL819x_2GHZ_CH01_11    \
55         REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
56
57 /*
58  *We enable active scan on these a case
59  *by case basis by regulatory domain
60  */
61 #define RTL819x_2GHZ_CH12_13    \
62         REG_RULE(2467-10, 2472+10, 40, 0, 20,\
63         NL80211_RRF_PASSIVE_SCAN)
64
65 #define RTL819x_2GHZ_CH14       \
66         REG_RULE(2484-10, 2484+10, 40, 0, 20, \
67         NL80211_RRF_PASSIVE_SCAN | \
68         NL80211_RRF_NO_OFDM)
69
70 /* 5G chan 36 - chan 64*/
71 #define RTL819x_5GHZ_5150_5350  \
72         REG_RULE(5150-10, 5350+10, 40, 0, 30, \
73         NL80211_RRF_PASSIVE_SCAN | \
74         NL80211_RRF_NO_IBSS)
75
76 /* 5G chan 100 - chan 165*/
77 #define RTL819x_5GHZ_5470_5850  \
78         REG_RULE(5470-10, 5850+10, 40, 0, 30, \
79         NL80211_RRF_PASSIVE_SCAN | \
80         NL80211_RRF_NO_IBSS)
81
82 /* 5G chan 149 - chan 165*/
83 #define RTL819x_5GHZ_5725_5850  \
84         REG_RULE(5725-10, 5850+10, 40, 0, 30, \
85         NL80211_RRF_PASSIVE_SCAN | \
86         NL80211_RRF_NO_IBSS)
87
88 #define RTL819x_5GHZ_ALL        \
89         (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
90
91 static const struct ieee80211_regdomain rtl_regdom_11 = {
92         .n_reg_rules = 1,
93         .alpha2 = "99",
94         .reg_rules = {
95                       RTL819x_2GHZ_CH01_11,
96                       }
97 };
98
99 static const struct ieee80211_regdomain rtl_regdom_12_13 = {
100         .n_reg_rules = 2,
101         .alpha2 = "99",
102         .reg_rules = {
103                       RTL819x_2GHZ_CH01_11,
104                           RTL819x_2GHZ_CH12_13,
105                       }
106 };
107
108 static const struct ieee80211_regdomain rtl_regdom_no_midband = {
109         .n_reg_rules = 3,
110         .alpha2 = "99",
111         .reg_rules = {
112                       RTL819x_2GHZ_CH01_11,
113                           RTL819x_5GHZ_5150_5350,
114                           RTL819x_5GHZ_5725_5850,
115                       }
116 };
117
118 static const struct ieee80211_regdomain rtl_regdom_60_64 = {
119         .n_reg_rules = 3,
120         .alpha2 = "99",
121         .reg_rules = {
122                       RTL819x_2GHZ_CH01_11,
123                           RTL819x_2GHZ_CH12_13,
124                           RTL819x_5GHZ_5725_5850,
125                       }
126 };
127
128 static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
129         .n_reg_rules = 4,
130         .alpha2 = "99",
131         .reg_rules = {
132                       RTL819x_2GHZ_CH01_11,
133                           RTL819x_2GHZ_CH12_13,
134                           RTL819x_2GHZ_CH14,
135                           RTL819x_5GHZ_5725_5850,
136                       }
137 };
138
139 static const struct ieee80211_regdomain rtl_regdom_12_13_5g_all = {
140         .n_reg_rules = 4,
141         .alpha2 = "99",
142         .reg_rules = {
143                         RTL819x_2GHZ_CH01_11,
144                         RTL819x_2GHZ_CH12_13,
145                         RTL819x_5GHZ_5150_5350,
146                         RTL819x_5GHZ_5470_5850,
147                 }
148 };
149
150 static const struct ieee80211_regdomain rtl_regdom_14 = {
151         .n_reg_rules = 3,
152         .alpha2 = "99",
153         .reg_rules = {
154                       RTL819x_2GHZ_CH01_11,
155                           RTL819x_2GHZ_CH12_13,
156                           RTL819x_2GHZ_CH14,
157                       }
158 };
159
160 static bool _rtl_is_radar_freq(u16 center_freq)
161 {
162         return (center_freq >= 5260 && center_freq <= 5700);
163 }
164
165 static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
166                                            enum nl80211_reg_initiator initiator)
167 {
168         enum ieee80211_band band;
169         struct ieee80211_supported_band *sband;
170         const struct ieee80211_reg_rule *reg_rule;
171         struct ieee80211_channel *ch;
172         unsigned int i;
173         u32 bandwidth = 0;
174         int r;
175
176         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
177
178                 if (!wiphy->bands[band])
179                         continue;
180
181                 sband = wiphy->bands[band];
182
183                 for (i = 0; i < sband->n_channels; i++) {
184                         ch = &sband->channels[i];
185                         if (_rtl_is_radar_freq(ch->center_freq) ||
186                             (ch->flags & IEEE80211_CHAN_RADAR))
187                                 continue;
188                         if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
189                                 r = freq_reg_info(wiphy, ch->center_freq,
190                                                   bandwidth, &reg_rule);
191                                 if (r)
192                                         continue;
193
194                                 /*
195                                  *If 11d had a rule for this channel ensure
196                                  *we enable adhoc/beaconing if it allows us to
197                                  *use it. Note that we would have disabled it
198                                  *by applying our static world regdomain by
199                                  *default during init, prior to calling our
200                                  *regulatory_hint().
201                                  */
202
203                                 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
204                                         ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
205                                 if (!(reg_rule->
206                                      flags & NL80211_RRF_PASSIVE_SCAN))
207                                         ch->flags &=
208                                             ~IEEE80211_CHAN_PASSIVE_SCAN;
209                         } else {
210                                 if (ch->beacon_found)
211                                         ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
212                                                   IEEE80211_CHAN_PASSIVE_SCAN);
213                         }
214                 }
215         }
216 }
217
218 /* Allows active scan scan on Ch 12 and 13 */
219 static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
220                                              enum nl80211_reg_initiator
221                                              initiator)
222 {
223         struct ieee80211_supported_band *sband;
224         struct ieee80211_channel *ch;
225         const struct ieee80211_reg_rule *reg_rule;
226         u32 bandwidth = 0;
227         int r;
228
229         if (!wiphy->bands[IEEE80211_BAND_2GHZ])
230                 return;
231         sband = wiphy->bands[IEEE80211_BAND_2GHZ];
232
233         /*
234          *If no country IE has been received always enable active scan
235          *on these channels. This is only done for specific regulatory SKUs
236          */
237         if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
238                 ch = &sband->channels[11];      /* CH 12 */
239                 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
240                         ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
241                 ch = &sband->channels[12];      /* CH 13 */
242                 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
243                         ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
244                 return;
245         }
246
247         /*
248          *If a country IE has been received check its rule for this
249          *channel first before enabling active scan. The passive scan
250          *would have been enforced by the initial processing of our
251          *custom regulatory domain.
252          */
253
254         ch = &sband->channels[11];      /* CH 12 */
255         r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
256         if (!r) {
257                 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
258                         if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
259                                 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
260         }
261
262         ch = &sband->channels[12];      /* CH 13 */
263         r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
264         if (!r) {
265                 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
266                         if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
267                                 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
268         }
269 }
270
271 /*
272  *Always apply Radar/DFS rules on
273  *freq range 5260 MHz - 5700 MHz
274  */
275 static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
276 {
277         struct ieee80211_supported_band *sband;
278         struct ieee80211_channel *ch;
279         unsigned int i;
280
281         if (!wiphy->bands[IEEE80211_BAND_5GHZ])
282                 return;
283
284         sband = wiphy->bands[IEEE80211_BAND_5GHZ];
285
286         for (i = 0; i < sband->n_channels; i++) {
287                 ch = &sband->channels[i];
288                 if (!_rtl_is_radar_freq(ch->center_freq))
289                         continue;
290
291                 /*
292                  *We always enable radar detection/DFS on this
293                  *frequency range. Additionally we also apply on
294                  *this frequency range:
295                  *- If STA mode does not yet have DFS supports disable
296                  * active scanning
297                  *- If adhoc mode does not support DFS yet then disable
298                  * adhoc in the frequency.
299                  *- If AP mode does not yet support radar detection/DFS
300                  *do not allow AP mode
301                  */
302                 if (!(ch->flags & IEEE80211_CHAN_DISABLED))
303                         ch->flags |= IEEE80211_CHAN_RADAR |
304                             IEEE80211_CHAN_NO_IBSS |
305                             IEEE80211_CHAN_PASSIVE_SCAN;
306         }
307 }
308
309 static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
310                                        enum nl80211_reg_initiator initiator,
311                                        struct rtl_regulatory *reg)
312 {
313         _rtl_reg_apply_beaconing_flags(wiphy, initiator);
314         _rtl_reg_apply_active_scan_flags(wiphy, initiator);
315         return;
316 }
317
318 static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
319                                    struct regulatory_request *request,
320                                    struct rtl_regulatory *reg)
321 {
322         /* We always apply this */
323         _rtl_reg_apply_radar_flags(wiphy);
324
325         switch (request->initiator) {
326         case NL80211_REGDOM_SET_BY_DRIVER:
327         case NL80211_REGDOM_SET_BY_CORE:
328         case NL80211_REGDOM_SET_BY_USER:
329                 break;
330         case NL80211_REGDOM_SET_BY_COUNTRY_IE:
331                 _rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
332                 break;
333         }
334
335         return 0;
336 }
337
338 static const struct ieee80211_regdomain *_rtl_regdomain_select(
339                                                struct rtl_regulatory *reg)
340 {
341         switch (reg->country_code) {
342         case COUNTRY_CODE_FCC:
343                 return &rtl_regdom_no_midband;
344         case COUNTRY_CODE_IC:
345                 return &rtl_regdom_11;
346         case COUNTRY_CODE_TELEC_NETGEAR:
347                 return &rtl_regdom_60_64;
348         case COUNTRY_CODE_ETSI:
349         case COUNTRY_CODE_SPAIN:
350         case COUNTRY_CODE_FRANCE:
351         case COUNTRY_CODE_ISRAEL:
352         case COUNTRY_CODE_WORLD_WIDE_13:
353                 return &rtl_regdom_12_13;
354         case COUNTRY_CODE_MKK:
355         case COUNTRY_CODE_MKK1:
356         case COUNTRY_CODE_TELEC:
357         case COUNTRY_CODE_MIC:
358                 return &rtl_regdom_14_60_64;
359         case COUNTRY_CODE_GLOBAL_DOMAIN:
360                 return &rtl_regdom_14;
361         case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL:
362                 return &rtl_regdom_12_13_5g_all;
363         default:
364                 return &rtl_regdom_no_midband;
365         }
366 }
367
368 static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
369                                 struct wiphy *wiphy,
370                                 int (*reg_notifier) (struct wiphy *wiphy,
371                                                      struct regulatory_request *
372                                                      request))
373 {
374         const struct ieee80211_regdomain *regd;
375
376         wiphy->reg_notifier = reg_notifier;
377
378         wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
379         wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
380         wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
381
382         regd = _rtl_regdomain_select(reg);
383         wiphy_apply_custom_regulatory(wiphy, regd);
384         _rtl_reg_apply_radar_flags(wiphy);
385         _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
386         return 0;
387 }
388
389 static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
390 {
391         int i;
392
393         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
394                 if (allCountries[i].countrycode == countrycode)
395                         return &allCountries[i];
396         }
397         return NULL;
398 }
399
400 static u8 channel_plan_to_country_code(u8 channelplan)
401 {
402         switch (channelplan) {
403         case 0x20:
404         case 0x21:
405                 return COUNTRY_CODE_WORLD_WIDE_13;
406         case 0x22:
407                 return COUNTRY_CODE_IC;
408         case 0x25:
409                 return COUNTRY_CODE_ETSI;
410         case 0x32:
411                 return COUNTRY_CODE_TELEC_NETGEAR;
412         case 0x41:
413                 return COUNTRY_CODE_GLOBAL_DOMAIN;
414         case 0x7f:
415                 return COUNTRY_CODE_WORLD_WIDE_13_5G_ALL;
416         default:
417                 return COUNTRY_CODE_MAX; /*Error*/
418         }
419 }
420
421 int rtl_regd_init(struct ieee80211_hw *hw,
422                   int (*reg_notifier) (struct wiphy *wiphy,
423                                        struct regulatory_request *request))
424 {
425         struct rtl_priv *rtlpriv = rtl_priv(hw);
426         struct wiphy *wiphy = hw->wiphy;
427         struct country_code_to_enum_rd *country = NULL;
428
429         if (wiphy == NULL || &rtlpriv->regd == NULL)
430                 return -EINVAL;
431
432         /* init country_code from efuse channel plan */
433         rtlpriv->regd.country_code =
434                 channel_plan_to_country_code(rtlpriv->efuse.channel_plan);
435
436         RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
437                  (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x conuntry code: %d\n",
438                  rtlpriv->efuse.channel_plan, rtlpriv->regd.country_code));
439
440         if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
441                 RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
442                          (KERN_DEBUG "rtl: EEPROM indicates invalid contry code"
443                           "world wide 13 should be used\n"));
444
445                 rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
446         }
447
448         country = _rtl_regd_find_country(rtlpriv->regd.country_code);
449
450         if (country) {
451                 rtlpriv->regd.alpha2[0] = country->iso_name[0];
452                 rtlpriv->regd.alpha2[1] = country->iso_name[1];
453         } else {
454                 rtlpriv->regd.alpha2[0] = '0';
455                 rtlpriv->regd.alpha2[1] = '0';
456         }
457
458         RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
459                  (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n",
460                   rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]));
461
462         _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
463
464         return 0;
465 }
466
467 int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
468 {
469         struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
470         struct rtl_priv *rtlpriv = rtl_priv(hw);
471
472         RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, ("\n"));
473
474         return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
475 }