net: wireless: rockchip_wlan: add rtl8723cs support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723cs / 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 nl80211_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[NL80211_BAND_2GHZ])
209                 return;
210         sband = wiphy->bands[NL80211_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[NL80211_BAND_5GHZ])
262                 return;
263
264         sband = wiphy->bands[NL80211_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 (!(ch->flags & IEEE80211_CHAN_DISABLED)
272                         #if defined(CONFIG_DFS_MASTER)
273                         && rtw_odm_dfs_domain_unknown(wiphy_to_adapter(wiphy))
274                         #endif
275                 ) {
276                         ch->flags |= IEEE80211_CHAN_RADAR;
277                         #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
278                         ch->flags |= (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
279                         #else
280                         ch->flags |= IEEE80211_CHAN_NO_IR;
281                         #endif
282                 }
283 #endif /* CONFIG_DFS */
284
285 #if 0
286                 /*
287                  * We always enable radar detection/DFS on this
288                  * frequency range. Additionally we also apply on
289                  * this frequency range:
290                  * - If STA mode does not yet have DFS supports disable
291                  *  active scanning
292                  * - If adhoc mode does not support DFS yet then disable
293                  *  adhoc in the frequency.
294                  * - If AP mode does not yet support radar detection/DFS
295                  *  do not allow AP mode
296                  */
297                 if (!(ch->flags & IEEE80211_CHAN_DISABLED))
298                         ch->flags |= IEEE80211_CHAN_RADAR |
299                                      IEEE80211_CHAN_NO_IBSS |
300                                      IEEE80211_CHAN_PASSIVE_SCAN;
301 #endif
302         }
303 }
304
305 static void _rtw_reg_apply_flags(struct wiphy *wiphy)
306 {
307 #if 1                           /* by channel plan */
308         _adapter *padapter = wiphy_to_adapter(wiphy);
309         u8 channel_plan = padapter->mlmepriv.ChannelPlan;
310         struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
311         RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set;
312         u8 max_chan_nums = pmlmeext->max_chan_nums;
313
314         struct ieee80211_supported_band *sband;
315         struct ieee80211_channel *ch;
316         unsigned int i, j;
317         u16 channel;
318         u32 freq;
319
320         /* all channels disable */
321         for (i = 0; i < NUM_NL80211_BANDS; i++) {
322                 sband = wiphy->bands[i];
323
324                 if (sband) {
325                         for (j = 0; j < sband->n_channels; j++) {
326                                 ch = &sband->channels[j];
327
328                                 if (ch)
329                                         ch->flags = IEEE80211_CHAN_DISABLED;
330                         }
331                 }
332         }
333
334         /* channels apply by channel plans. */
335         for (i = 0; i < max_chan_nums; i++) {
336                 channel = channel_set[i].ChannelNum;
337                 freq = rtw_ch2freq(channel);
338
339                 ch = ieee80211_get_channel(wiphy, freq);
340                 if (ch) {
341                         if (channel_set[i].ScanType == SCAN_PASSIVE
342                                 #if defined(CONFIG_DFS_MASTER)
343                                 && rtw_odm_dfs_domain_unknown(wiphy_to_adapter(wiphy))
344                                 #endif
345                         ) {
346                                 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
347                                 ch->flags = (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
348                                 #else
349                                 ch->flags = IEEE80211_CHAN_NO_IR;
350                                 #endif
351                         } else
352                                 ch->flags = 0;
353                 }
354         }
355
356 #else
357         struct ieee80211_supported_band *sband;
358         struct ieee80211_channel *ch;
359         unsigned int i, j;
360         u16 channels[37] = {
361                 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56,
362                 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140,
363                 149, 153,
364                 157, 161, 165
365         };
366         u16 channel;
367         u32 freq;
368
369         for (i = 0; i < NUM_NL80211_BANDS; i++) {
370                 sband = wiphy->bands[i];
371
372                 if (sband)
373                         for (j = 0; j < sband->n_channels; j++) {
374                                 ch = &sband->channels[j];
375
376                                 if (ch)
377                                         ch->flags = IEEE80211_CHAN_DISABLED;
378                         }
379         }
380
381         for (i = 0; i < 37; i++) {
382                 channel = channels[i];
383                 freq = rtw_ch2freq(channel);
384
385                 ch = ieee80211_get_channel(wiphy, freq);
386                 if (ch) {
387                         if (channel <= 11)
388                                 ch->flags = 0;
389                         else
390                                 ch->flags = 0;  /* IEEE80211_CHAN_PASSIVE_SCAN; */
391                 }
392                 /* printk("%s: freq %d(%d) flag 0x%02X\n", __func__, freq, channel, ch->flags); */
393         }
394 #endif
395 }
396
397 static void _rtw_reg_apply_world_flags(struct wiphy *wiphy,
398                                        enum nl80211_reg_initiator initiator,
399                                        struct rtw_regulatory *reg)
400 {
401         /* _rtw_reg_apply_beaconing_flags(wiphy, initiator); */
402         /* _rtw_reg_apply_active_scan_flags(wiphy, initiator); */
403         return;
404 }
405
406 static int _rtw_reg_notifier_apply(struct wiphy *wiphy,
407                                    struct regulatory_request *request,
408                                    struct rtw_regulatory *reg)
409 {
410
411         /* Hard code flags */
412         _rtw_reg_apply_flags(wiphy);
413
414         /* We always apply this */
415         _rtw_reg_apply_radar_flags(wiphy);
416
417         switch (request->initiator) {
418         case NL80211_REGDOM_SET_BY_DRIVER:
419                 RTW_INFO("%s: %s\n", __func__, "NL80211_REGDOM_SET_BY_DRIVER");
420                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
421                                            reg);
422                 break;
423         case NL80211_REGDOM_SET_BY_CORE:
424                 RTW_INFO("%s: %s\n", __func__,
425                          "NL80211_REGDOM_SET_BY_CORE to DRV");
426                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
427                                            reg);
428                 break;
429         case NL80211_REGDOM_SET_BY_USER:
430                 RTW_INFO("%s: %s\n", __func__,
431                          "NL80211_REGDOM_SET_BY_USER to DRV");
432                 _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
433                                            reg);
434                 break;
435         case NL80211_REGDOM_SET_BY_COUNTRY_IE:
436                 RTW_INFO("%s: %s\n", __func__,
437                          "NL80211_REGDOM_SET_BY_COUNTRY_IE");
438                 _rtw_reg_apply_world_flags(wiphy, request->initiator, reg);
439                 break;
440         }
441
442         return 0;
443 }
444
445 static const struct ieee80211_regdomain *_rtw_regdomain_select(struct
446                 rtw_regulatory
447                 *reg)
448 {
449 #if 0
450         switch (reg->country_code) {
451         case COUNTRY_CODE_USER:
452         default:
453                 return &rtw_regdom_rd;
454         }
455 #else
456         return &rtw_regdom_rd;
457 #endif
458 }
459
460 void _rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
461 {
462         struct rtw_regulatory *reg = NULL;
463
464         RTW_INFO("%s\n", __func__);
465
466         _rtw_reg_notifier_apply(wiphy, request, reg);
467 }
468
469 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
470 int rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
471 #else
472 void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
473 #endif
474 {
475         _rtw_reg_notifier(wiphy, request);
476 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
477         return 0;
478 #endif
479 }
480
481 void rtw_reg_notify_by_driver(_adapter *adapter)
482 {
483         if ((adapter->rtw_wdev != NULL) && (adapter->rtw_wdev->wiphy)) {
484                 struct regulatory_request request;
485                 request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
486                 rtw_reg_notifier(adapter->rtw_wdev->wiphy, &request);
487         }
488 }
489
490 static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy)
491 {
492         const struct ieee80211_regdomain *regd;
493
494         wiphy->reg_notifier = rtw_reg_notifier;
495
496 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
497         wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
498         wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
499         wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
500 #else
501         wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
502         wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
503         wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
504 #endif
505
506         regd = _rtw_regdomain_select(reg);
507         wiphy_apply_custom_regulatory(wiphy, regd);
508
509         /* Hard code flags */
510         _rtw_reg_apply_flags(wiphy);
511         _rtw_reg_apply_radar_flags(wiphy);
512         _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
513 }
514
515 static struct country_code_to_enum_rd *_rtw_regd_find_country(u16 countrycode)
516 {
517         int i;
518
519         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
520                 if (allCountries[i].countrycode == countrycode)
521                         return &allCountries[i];
522         }
523         return NULL;
524 }
525
526 int rtw_regd_init(_adapter *padapter)
527 {
528         struct wiphy *wiphy = padapter->rtw_wdev->wiphy;
529
530 #if 0
531         if (rtw_regd == NULL) {
532                 rtw_regd = (struct rtw_regulatory *)
533                            rtw_malloc(sizeof(struct rtw_regulatory));
534
535                 rtw_regd->alpha2[0] = '9';
536                 rtw_regd->alpha2[1] = '9';
537
538                 rtw_regd->country_code = COUNTRY_CODE_USER;
539         }
540
541         RTW_INFO("%s: Country alpha2 being used: %c%c\n",
542                  __func__, rtw_regd->alpha2[0], rtw_regd->alpha2[1]);
543 #endif
544
545         _rtw_regd_init_wiphy(NULL, wiphy);
546
547         return 0;
548 }
549 #endif /* CONFIG_IOCTL_CFG80211 */