net: wireless: rockchip_wlan: add rtl8723ds support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723ds / os_dep / linux / wifi_regd.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  *****************************************************************************/
6
7 #include <drv_types.h>
8
9 #ifdef CONFIG_IOCTL_CFG80211
10
11 #include <rtw_wifi_regd.h>
12
13 static struct country_code_to_enum_rd allCountries[] = {
14         {COUNTRY_CODE_USER, "RD"},
15 };
16
17 /*
18  * REG_RULE(freq start, freq end, bandwidth, max gain, eirp, reg_flags)
19  */
20
21 /*
22  *Only these channels all allow active
23  *scan on all world regulatory domains
24  */
25
26 /* 2G chan 01 - chan 11 */
27 #define RTW_2GHZ_CH01_11        \
28         REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
29
30 /*
31  *We enable active scan on these a case
32  *by case basis by regulatory domain
33  */
34
35 /* 2G chan 12 - chan 13, PASSIV SCAN */
36 #define RTW_2GHZ_CH12_13        \
37         REG_RULE(2467-10, 2472+10, 40, 0, 20,   \
38                  NL80211_RRF_PASSIVE_SCAN)
39
40 /* 2G chan 14, PASSIVS SCAN, NO OFDM (B only) */
41 #define RTW_2GHZ_CH14   \
42         REG_RULE(2484-10, 2484+10, 40, 0, 20,   \
43                  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
44
45 /* 5G chan 36 - chan 64 */
46 #define RTW_5GHZ_5150_5350      \
47         REG_RULE(5150-10, 5350+10, 40, 0, 30,   \
48                  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
49
50 /* 5G chan 100 - chan 165 */
51 #define RTW_5GHZ_5470_5850      \
52         REG_RULE(5470-10, 5850+10, 40, 0, 30, \
53                  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
54
55 /* 5G chan 149 - chan 165 */
56 #define RTW_5GHZ_5725_5850      \
57         REG_RULE(5725-10, 5850+10, 40, 0, 30, \
58                  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
59
60 /* 5G chan 36 - chan 165 */
61 #define RTW_5GHZ_5150_5850      \
62         REG_RULE(5150-10, 5850+10, 40, 0, 30,   \
63                  NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
64
65 static const struct ieee80211_regdomain rtw_regdom_rd = {
66         .n_reg_rules = 3,
67         .alpha2 = "99",
68         .reg_rules = {
69                 RTW_2GHZ_CH01_11,
70                 RTW_2GHZ_CH12_13,
71                 RTW_5GHZ_5150_5850,
72         }
73 };
74
75 static const struct ieee80211_regdomain rtw_regdom_11 = {
76         .n_reg_rules = 1,
77         .alpha2 = "99",
78         .reg_rules = {
79                 RTW_2GHZ_CH01_11,
80         }
81 };
82
83 static const struct ieee80211_regdomain rtw_regdom_12_13 = {
84         .n_reg_rules = 2,
85         .alpha2 = "99",
86         .reg_rules = {
87                 RTW_2GHZ_CH01_11,
88                 RTW_2GHZ_CH12_13,
89         }
90 };
91
92 static const struct ieee80211_regdomain rtw_regdom_no_midband = {
93         .n_reg_rules = 3,
94         .alpha2 = "99",
95         .reg_rules = {
96                 RTW_2GHZ_CH01_11,
97                 RTW_5GHZ_5150_5350,
98                 RTW_5GHZ_5725_5850,
99         }
100 };
101
102 static const struct ieee80211_regdomain rtw_regdom_60_64 = {
103         .n_reg_rules = 3,
104         .alpha2 = "99",
105         .reg_rules = {
106                 RTW_2GHZ_CH01_11,
107                 RTW_2GHZ_CH12_13,
108                 RTW_5GHZ_5725_5850,
109         }
110 };
111
112 static const struct ieee80211_regdomain rtw_regdom_14_60_64 = {
113         .n_reg_rules = 4,
114         .alpha2 = "99",
115         .reg_rules = {
116                 RTW_2GHZ_CH01_11,
117                 RTW_2GHZ_CH12_13,
118                 RTW_2GHZ_CH14,
119                 RTW_5GHZ_5725_5850,
120         }
121 };
122
123 static const struct ieee80211_regdomain rtw_regdom_14 = {
124         .n_reg_rules = 3,
125         .alpha2 = "99",
126         .reg_rules = {
127                 RTW_2GHZ_CH01_11,
128                 RTW_2GHZ_CH12_13,
129                 RTW_2GHZ_CH14,
130         }
131 };
132
133 #if 0
134 static struct rtw_regulatory *rtw_regd;
135 #endif
136
137 static bool _rtw_is_radar_freq(u16 center_freq)
138 {
139         return center_freq >= 5260 && center_freq <= 5700;
140 }
141
142 #if 0 /* not_yet */
143 static void _rtw_reg_apply_beaconing_flags(struct wiphy *wiphy,
144                 enum nl80211_reg_initiator initiator)
145 {
146         enum ieee80211_band band;
147         struct ieee80211_supported_band *sband;
148         const struct ieee80211_reg_rule *reg_rule;
149         struct ieee80211_channel *ch;
150         unsigned int i;
151         u32 bandwidth = 0;
152         int r;
153
154         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
155
156                 if (!wiphy->bands[band])
157                         continue;
158
159                 sband = wiphy->bands[band];
160
161                 for (i = 0; i < sband->n_channels; i++) {
162                         ch = &sband->channels[i];
163                         if (_rtw_is_radar_freq(ch->center_freq) ||
164                             (ch->flags & IEEE80211_CHAN_RADAR))
165                                 continue;
166                         if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
167                                 r = freq_reg_info(wiphy, ch->center_freq,
168                                                   bandwidth, &reg_rule);
169                                 if (r)
170                                         continue;
171
172                                 /*
173                                  *If 11d had a rule for this channel ensure
174                                  *we enable adhoc/beaconing if it allows us to
175                                  *use it. Note that we would have disabled it
176                                  *by applying our static world regdomain by
177                                  *default during init, prior to calling our
178                                  *regulatory_hint().
179                                  */
180
181                                 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
182                                         ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
183                                 if (!
184                                     (reg_rule->flags &
185                                      NL80211_RRF_PASSIVE_SCAN))
186                                         ch->flags &=
187                                                 ~IEEE80211_CHAN_PASSIVE_SCAN;
188                         } else {
189                                 if (ch->beacon_found)
190                                         ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
191                                                 IEEE80211_CHAN_PASSIVE_SCAN);
192                         }
193                 }
194         }
195 }
196
197 /* Allows active scan scan on Ch 12 and 13 */
198 static void _rtw_reg_apply_active_scan_flags(struct wiphy *wiphy,
199                 enum nl80211_reg_initiator
200                 initiator)
201 {
202         struct ieee80211_supported_band *sband;
203         struct ieee80211_channel *ch;
204         const struct ieee80211_reg_rule *reg_rule;
205         u32 bandwidth = 0;
206         int r;
207
208         if (!wiphy->bands[IEEE80211_BAND_2GHZ])
209                 return;
210         sband = wiphy->bands[IEEE80211_BAND_2GHZ];
211
212         /*
213          * If no country IE has been received always enable active scan
214          * on these channels. This is only done for specific regulatory SKUs
215          */
216         if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
217                 ch = &sband->channels[11];      /* CH 12 */
218                 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
219                         ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
220                 ch = &sband->channels[12];      /* CH 13 */
221                 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
222                         ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
223                 return;
224         }
225
226         /*
227          * If a country IE has been received check its rule for this
228          * channel first before enabling active scan. The passive scan
229          * would have been enforced by the initial processing of our
230          * custom regulatory domain.
231          */
232
233         ch = &sband->channels[11];      /* CH 12 */
234         r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
235         if (!r) {
236                 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
237                         if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
238                                 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
239         }
240
241         ch = &sband->channels[12];      /* CH 13 */
242         r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
243         if (!r) {
244                 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
245                         if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
246                                 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
247         }
248 }
249 #endif
250
251 /*
252  * Always apply Radar/DFS rules on
253  * freq range 5260 MHz - 5700 MHz
254  */
255 static void _rtw_reg_apply_radar_flags(struct wiphy *wiphy)
256 {
257         struct ieee80211_supported_band *sband;
258         struct ieee80211_channel *ch;
259         unsigned int i;
260
261         if (!wiphy->bands[IEEE80211_BAND_5GHZ])
262                 return;
263
264         sband = wiphy->bands[IEEE80211_BAND_5GHZ];
265
266         for (i = 0; i < sband->n_channels; i++) {
267                 ch = &sband->channels[i];
268                 if (!_rtw_is_radar_freq(ch->center_freq))
269                         continue;
270 #ifdef CONFIG_DFS
271                 #if !defined(CONFIG_DFS_MASTER)
272                 if (!(ch->flags & IEEE80211_CHAN_DISABLED)) {
273                         ch->flags |= IEEE80211_CHAN_RADAR;
274                         #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
275                         ch->flags |= (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
276                         #else
277                         ch->flags |= IEEE80211_CHAN_NO_IR;
278                         #endif
279                 }
280                 #endif
281 #endif /* CONFIG_DFS */
282
283 #if 0
284                 /*
285                  * We always enable radar detection/DFS on this
286                  * frequency range. Additionally we also apply on
287                  * this frequency range:
288                  * - If STA mode does not yet have DFS supports disable
289                  *  active scanning
290                  * - If adhoc mode does not support DFS yet then disable
291                  *  adhoc in the frequency.
292                  * - If AP mode does not yet support radar detection/DFS
293                  *  do not allow AP mode
294                  */
295                 if (!(ch->flags & IEEE80211_CHAN_DISABLED))
296                         ch->flags |= IEEE80211_CHAN_RADAR |
297                                      IEEE80211_CHAN_NO_IBSS |
298                                      IEEE80211_CHAN_PASSIVE_SCAN;
299 #endif
300         }
301 }
302
303 static void _rtw_reg_apply_flags(struct wiphy *wiphy)
304 {
305 #if 1                           /* by channel plan */
306         _adapter *padapter = wiphy_to_adapter(wiphy);
307         u8 channel_plan = padapter->mlmepriv.ChannelPlan;
308         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
309         RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set;
310         u8 max_chan_nums = pmlmeext->max_chan_nums;
311
312         struct ieee80211_supported_band *sband;
313         struct ieee80211_channel *ch;
314         unsigned int i, j;
315         u16 channel;
316         u32 freq;
317
318         /* all channels disable */
319         for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
320                 sband = wiphy->bands[i];
321
322                 if (sband) {
323                         for (j = 0; j < sband->n_channels; j++) {
324                                 ch = &sband->channels[j];
325
326                                 if (ch)
327                                         ch->flags = IEEE80211_CHAN_DISABLED;
328                         }
329                 }
330         }
331
332         /* channels apply by channel plans. */
333         for (i = 0; i < max_chan_nums; i++) {
334                 channel = channel_set[i].ChannelNum;
335                 freq = rtw_ch2freq(channel);
336
337                 ch = ieee80211_get_channel(wiphy, freq);
338                 if (ch) {
339                         if (channel_set[i].ScanType == SCAN_PASSIVE) {
340                                 #if defined(CONFIG_DFS_MASTER)
341                                 ch->flags = 0;
342                                 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
343                                 ch->flags = (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
344                                 #else
345                                 ch->flags = IEEE80211_CHAN_NO_IR;
346                                 #endif
347                         } else
348                                 ch->flags = 0;
349                 }
350         }
351
352 #else
353         struct ieee80211_supported_band *sband;
354         struct ieee80211_channel *ch;
355         unsigned int i, j;
356         u16 channels[37] = {
357                 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56,
358                 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140,
359                 149, 153,
360                 157, 161, 165
361         };
362         u16 channel;
363         u32 freq;
364
365         for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
366                 sband = wiphy->bands[i];
367
368                 if (sband)
369                         for (j = 0; j < sband->n_channels; j++) {
370                                 ch = &sband->channels[j];
371
372                                 if (ch)
373                                         ch->flags = IEEE80211_CHAN_DISABLED;
374                         }
375         }
376
377         for (i = 0; i < 37; i++) {
378                 channel = channels[i];
379                 freq = rtw_ch2freq(channel);
380
381                 ch = ieee80211_get_channel(wiphy, freq);
382                 if (ch) {
383                         if (channel <= 11)
384                                 ch->flags = 0;
385                         else
386                                 ch->flags = 0;  /* IEEE80211_CHAN_PASSIVE_SCAN; */
387                 }
388                 /* printk("%s: freq %d(%d) flag 0x%02X\n", __func__, freq, channel, ch->flags); */
389         }
390 #endif
391 }
392
393 static void _rtw_reg_apply_world_flags(struct wiphy *wiphy,
394                                        enum nl80211_reg_initiator initiator,
395                                        struct rtw_regulatory *reg)
396 {
397         /* _rtw_reg_apply_beaconing_flags(wiphy, initiator); */
398         /* _rtw_reg_apply_active_scan_flags(wiphy, initiator); */
399         return;
400 }
401
402 static int _rtw_reg_notifier_apply(struct wiphy *wiphy,
403                                    struct regulatory_request *request,
404                                    struct rtw_regulatory *reg)
405 {
406
407         /* Hard code flags */
408         _rtw_reg_apply_flags(wiphy);
409
410         /* We always apply this */
411         _rtw_reg_apply_radar_flags(wiphy);
412
413         switch (request->initiator) {
414         case NL80211_REGDOM_SET_BY_DRIVER:
415                 RTW_INFO("%s: %s\n", __func__, "NL80211_REGDOM_SET_BY_DRIVER");
416                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
417                                            reg);
418                 break;
419         case NL80211_REGDOM_SET_BY_CORE:
420                 RTW_INFO("%s: %s\n", __func__,
421                          "NL80211_REGDOM_SET_BY_CORE to DRV");
422                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
423                                            reg);
424                 break;
425         case NL80211_REGDOM_SET_BY_USER:
426                 RTW_INFO("%s: %s\n", __func__,
427                          "NL80211_REGDOM_SET_BY_USER to DRV");
428                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
429                                            reg);
430                 break;
431         case NL80211_REGDOM_SET_BY_COUNTRY_IE:
432                 RTW_INFO("%s: %s\n", __func__,
433                          "NL80211_REGDOM_SET_BY_COUNTRY_IE");
434                 _rtw_reg_apply_world_flags(wiphy, request->initiator, reg);
435                 break;
436         }
437
438         return 0;
439 }
440
441 static const struct ieee80211_regdomain *_rtw_regdomain_select(struct
442                 rtw_regulatory
443                 *reg)
444 {
445 #if 0
446         switch (reg->country_code) {
447         case COUNTRY_CODE_USER:
448         default:
449                 return &rtw_regdom_rd;
450         }
451 #else
452         return &rtw_regdom_rd;
453 #endif
454 }
455
456 void _rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
457 {
458         struct rtw_regulatory *reg = NULL;
459
460         RTW_INFO("%s\n", __func__);
461
462         _rtw_reg_notifier_apply(wiphy, request, reg);
463 }
464
465 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
466 int rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
467 #else
468 void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
469 #endif
470 {
471         _rtw_reg_notifier(wiphy, request);
472 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
473         return 0;
474 #endif
475 }
476
477 void rtw_reg_notify_by_driver(_adapter *adapter)
478 {
479         if ((adapter->rtw_wdev != NULL) && (adapter->rtw_wdev->wiphy)) {
480                 struct regulatory_request request;
481                 request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
482                 rtw_reg_notifier(adapter->rtw_wdev->wiphy, &request);
483         }
484 }
485
486 static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy)
487 {
488         const struct ieee80211_regdomain *regd;
489
490         wiphy->reg_notifier = rtw_reg_notifier;
491
492 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
493         wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
494         wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
495         wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
496 #else
497         wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
498         wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
499         wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
500 #endif
501
502         regd = _rtw_regdomain_select(reg);
503         wiphy_apply_custom_regulatory(wiphy, regd);
504
505         /* Hard code flags */
506         _rtw_reg_apply_flags(wiphy);
507         _rtw_reg_apply_radar_flags(wiphy);
508         _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
509 }
510
511 static struct country_code_to_enum_rd *_rtw_regd_find_country(u16 countrycode)
512 {
513         int i;
514
515         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
516                 if (allCountries[i].countrycode == countrycode)
517                         return &allCountries[i];
518         }
519         return NULL;
520 }
521
522 int rtw_regd_init(_adapter *padapter)
523 {
524         struct wiphy *wiphy = padapter->rtw_wdev->wiphy;
525
526 #if 0
527         if (rtw_regd == NULL) {
528                 rtw_regd = (struct rtw_regulatory *)
529                            rtw_malloc(sizeof(struct rtw_regulatory));
530
531                 rtw_regd->alpha2[0] = '9';
532                 rtw_regd->alpha2[1] = '9';
533
534                 rtw_regd->country_code = COUNTRY_CODE_USER;
535         }
536
537         RTW_INFO("%s: Country alpha2 being used: %c%c\n",
538                  __func__, rtw_regd->alpha2[0], rtw_regd->alpha2[1]);
539 #endif
540
541         _rtw_regd_init_wiphy(NULL, wiphy);
542
543         return 0;
544 }
545 #endif /* CONFIG_IOCTL_CFG80211 */