blob: bc975e8be1b6a36e0f45d0a9ee4b593f7ea441a0 [file] [log] [blame]
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -07001/*
2 * Misc utility routines used by kernel or app-level.
3 * Contents are wifi-specific, used by any kernel or app-level
4 * software that might want wifi things as it grows.
5 *
Steve Mucklef132c6c2012-06-06 18:30:57 -07006 * Copyright (C) 1999-2012, Broadcom Corporation
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -07007 *
Steve Mucklef132c6c2012-06-06 18:30:57 -07008 * Unless you and Broadcom execute a separate written software license
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -07009 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
Steve Mucklef132c6c2012-06-06 18:30:57 -070025 * $Id: bcmwifi.c 309193 2012-01-19 00:03:57Z $
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -070026 */
27
Steve Mucklef132c6c2012-06-06 18:30:57 -070028#include <bcm_cfg.h>
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -070029#include <typedefs.h>
30
31#ifdef BCMDRIVER
32#include <osl.h>
33#include <bcmutils.h>
34#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
35#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
36#else
37#include <stdio.h>
38#include <stdlib.h>
39#include <ctype.h>
40#ifndef ASSERT
41#define ASSERT(exp)
42#endif
43#endif
44#include <bcmwifi.h>
45
46#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
47#include <bcmstdlib.h>
48#endif
49
Steve Mucklef132c6c2012-06-06 18:30:57 -070050#ifndef D11AC_IOTYPES
51
52
53
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -070054
55
56
57
58char *
59wf_chspec_ntoa(chanspec_t chspec, char *buf)
60{
61 const char *band, *bw, *sb;
62 uint channel;
63
64 band = "";
65 bw = "";
66 sb = "";
67 channel = CHSPEC_CHANNEL(chspec);
68
69 if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
70 (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
71 band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
72 if (CHSPEC_IS40(chspec)) {
73 if (CHSPEC_SB_UPPER(chspec)) {
74 sb = "u";
75 channel += CH_10MHZ_APART;
76 } else {
77 sb = "l";
78 channel -= CH_10MHZ_APART;
79 }
80 } else if (CHSPEC_IS10(chspec)) {
81 bw = "n";
82 }
83
84
85 snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
86 return (buf);
87}
88
89
90chanspec_t
Steve Mucklef132c6c2012-06-06 18:30:57 -070091wf_chspec_aton(const char *a)
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -070092{
93 char *endp = NULL;
94 uint channel, band, bw, ctl_sb;
95 char c;
96
97 channel = strtoul(a, &endp, 10);
98
99
100 if (endp == a)
101 return 0;
102
103 if (channel > MAXCHANNEL)
104 return 0;
105
106 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
107 bw = WL_CHANSPEC_BW_20;
108 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
109
110 a = endp;
111
112 c = tolower(a[0]);
113 if (c == '\0')
114 goto done;
115
116
117 if (c == 'a' || c == 'b') {
118 band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
119 a++;
120 c = tolower(a[0]);
121 if (c == '\0')
122 goto done;
123 }
124
125
126 if (c == 'n') {
127 bw = WL_CHANSPEC_BW_10;
128 } else if (c == 'l') {
129 bw = WL_CHANSPEC_BW_40;
130 ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
131
132 if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
133 channel += CH_10MHZ_APART;
134 else
135 return 0;
136 } else if (c == 'u') {
137 bw = WL_CHANSPEC_BW_40;
138 ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
139
140 if (channel > CH_20MHZ_APART)
141 channel -= CH_10MHZ_APART;
142 else
143 return 0;
144 } else {
145 return 0;
146 }
147
148done:
149 return (channel | band | bw | ctl_sb);
150}
151
152
153bool
154wf_chspec_malformed(chanspec_t chanspec)
155{
156
157 if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
158 return TRUE;
159
160 if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
161 return TRUE;
162
163
Steve Mucklef132c6c2012-06-06 18:30:57 -0700164 if (CHSPEC_IS20(chanspec)) {
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -0700165 if (!CHSPEC_SB_NONE(chanspec))
166 return TRUE;
167 } else {
168 if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec))
169 return TRUE;
170 }
171
172 return FALSE;
173}
174
175
176uint8
177wf_chspec_ctlchan(chanspec_t chspec)
178{
179 uint8 ctl_chan;
180
181
182 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
183 return CHSPEC_CHANNEL(chspec);
184 } else {
185
186 ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40);
187
188 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
189
190 ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
191 } else {
192 ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER);
193
194 ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
195 }
196 }
197
198 return ctl_chan;
199}
200
201chanspec_t
202wf_chspec_ctlchspec(chanspec_t chspec)
203{
204 chanspec_t ctl_chspec = 0;
205 uint8 channel;
206
207 ASSERT(!wf_chspec_malformed(chspec));
208
209
210 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
211 return chspec;
212 } else {
213 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
214 channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
215 } else {
216 channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
217 }
218 ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
219 ctl_chspec |= CHSPEC_BAND(chspec);
220 }
221 return ctl_chspec;
222}
223
Steve Mucklef132c6c2012-06-06 18:30:57 -0700224#else
225
226
227
228
229
230
231static const char *wf_chspec_bw_str[] =
232{
233 "5",
234 "10",
235 "20",
236 "40",
237 "80",
238 "160",
239 "80+80",
240 "na"
241};
242
243static const uint8 wf_chspec_bw_mhz[] =
244{5, 10, 20, 40, 80, 160, 160};
245
246#define WF_NUM_BW \
247 (sizeof(wf_chspec_bw_mhz)/sizeof(uint8))
248
249
250static const uint8 wf_5g_40m_chans[] =
251{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159};
252#define WF_NUM_5G_40M_CHANS \
253 (sizeof(wf_5g_40m_chans)/sizeof(uint8))
254
255
256static const uint8 wf_5g_80m_chans[] =
257{42, 58, 106, 122, 138, 155};
258#define WF_NUM_5G_80M_CHANS \
259 (sizeof(wf_5g_80m_chans)/sizeof(uint8))
260
261
262static const uint8 wf_5g_160m_chans[] =
263{50, 114};
264#define WF_NUM_5G_160M_CHANS \
265 (sizeof(wf_5g_160m_chans)/sizeof(uint8))
266
267
268
269static uint
270bw_chspec_to_mhz(chanspec_t chspec)
271{
272 uint bw;
273
274 bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT;
275 return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]);
276}
277
278
279static uint8
280center_chan_to_edge(uint bw)
281{
282
283 return (uint8)(((bw - 20) / 2) / 5);
284}
285
286
287static uint8
288channel_low_edge(uint center_ch, uint bw)
289{
290 return (uint8)(center_ch - center_chan_to_edge(bw));
291}
292
293
294static int
295channel_to_sb(uint center_ch, uint ctl_ch, uint bw)
296{
297 uint lowest = channel_low_edge(center_ch, bw);
298 uint sb;
299
300 if ((ctl_ch - lowest) % 4) {
301
302 return -1;
303 }
304
305 sb = ((ctl_ch - lowest) / 4);
306
307
308 if (sb >= (bw / 20)) {
309
310 return -1;
311 }
312
313 return sb;
314}
315
316
317static uint8
318channel_to_ctl_chan(uint center_ch, uint bw, uint sb)
319{
320 return (uint8)(channel_low_edge(center_ch, bw) + sb * 4);
321}
322
323
324static int
325channel_80mhz_to_id(uint ch)
326{
327 uint i;
328 for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) {
329 if (ch == wf_5g_80m_chans[i])
330 return i;
331 }
332
333 return -1;
334}
335
336
337char *
338wf_chspec_ntoa(chanspec_t chspec, char *buf)
339{
340 const char *band;
341 uint ctl_chan;
342
343 if (wf_chspec_malformed(chspec))
344 return NULL;
345
346 band = "";
347
348
349 if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) ||
350 (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL))
351 band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g";
352
353
354 ctl_chan = wf_chspec_ctlchan(chspec);
355
356
357 if (CHSPEC_IS20(chspec)) {
358 snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan);
359 } else if (!CHSPEC_IS8080(chspec)) {
360 const char *bw;
361 const char *sb = "";
362
363 bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT];
364
365#ifdef CHANSPEC_NEW_40MHZ_FORMAT
366
367 if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) {
368 sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
369 }
370
371 snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb);
372#else
373
374 if (CHSPEC_IS40(chspec)) {
375 sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
376 snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb);
377 } else {
378 snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw);
379 }
380#endif
381
382 } else {
383
384 uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT;
385 uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT;
386
387
388 chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0;
389 chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0;
390
391
392 snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2);
393 }
394
395 return (buf);
396}
397
398static int
399read_uint(const char **p, unsigned int *num)
400{
401 unsigned long val;
402 char *endp = NULL;
403
404 val = strtoul(*p, &endp, 10);
405
406 if (endp == *p)
407 return 0;
408
409
410 *p = endp;
411
412 *num = (unsigned int)val;
413
414 return 1;
415}
416
417
418chanspec_t
419wf_chspec_aton(const char *a)
420{
421 chanspec_t chspec;
422 uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb;
423 uint num, ctl_ch;
424 uint ch1, ch2;
425 char c, sb_ul = '\0';
426 int i;
427
428 bw = 20;
429 chspec_sb = 0;
430 chspec_ch = ch1 = ch2 = 0;
431
432
433 if (!read_uint(&a, &num))
434 return 0;
435
436
437 c = tolower(a[0]);
438 if (c == 'g') {
439 a ++;
440
441
442 if (num == 2)
443 chspec_band = WL_CHANSPEC_BAND_2G;
444 else if (num == 5)
445 chspec_band = WL_CHANSPEC_BAND_5G;
446 else
447 return 0;
448
449
450 if (!read_uint(&a, &ctl_ch))
451 return 0;
452
453 c = tolower(a[0]);
454 }
455 else {
456
457 ctl_ch = num;
458 chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ?
459 WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
460 }
461
462 if (c == '\0') {
463
464 chspec_bw = WL_CHANSPEC_BW_20;
465 goto done_read;
466 }
467
468 a ++;
469
470
471 if (c == 'u' || c == 'l') {
472 sb_ul = c;
473 chspec_bw = WL_CHANSPEC_BW_40;
474 goto done_read;
475 }
476
477
478 if (c != '/')
479 return 0;
480
481
482 if (!read_uint(&a, &bw))
483 return 0;
484
485
486 if (bw == 20) {
487 chspec_bw = WL_CHANSPEC_BW_20;
488 } else if (bw == 40) {
489 chspec_bw = WL_CHANSPEC_BW_40;
490 } else if (bw == 80) {
491 chspec_bw = WL_CHANSPEC_BW_80;
492 } else if (bw == 160) {
493 chspec_bw = WL_CHANSPEC_BW_160;
494 } else {
495 return 0;
496 }
497
498
499
500 c = tolower(a[0]);
501
502
503 if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) {
504 if (c == 'u' || c == 'l') {
505 a ++;
506 sb_ul = c;
507 goto done_read;
508 }
509 }
510
511
512 if (c == '+') {
513
514 static const char *plus80 = "80/";
515
516
517 chspec_bw = WL_CHANSPEC_BW_8080;
518
519 a ++;
520
521
522 for (i = 0; i < 3; i++) {
523 if (*a++ != *plus80++) {
524 return 0;
525 }
526 }
527
528
529 if (!read_uint(&a, &ch1))
530 return 0;
531
532
533 if (a[0] != '-')
534 return 0;
535 a ++;
536
537
538 if (!read_uint(&a, &ch2))
539 return 0;
540 }
541
542done_read:
543
544 while (a[0] == ' ') {
545 a ++;
546 }
547
548
549 if (a[0] != '\0')
550 return 0;
551
552
553
554
555 if (sb_ul != '\0') {
556 if (sb_ul == 'l') {
557 chspec_ch = UPPER_20_SB(ctl_ch);
558 chspec_sb = WL_CHANSPEC_CTL_SB_LLL;
559 } else if (sb_ul == 'u') {
560 chspec_ch = LOWER_20_SB(ctl_ch);
561 chspec_sb = WL_CHANSPEC_CTL_SB_LLU;
562 }
563 }
564
565 else if (chspec_bw == WL_CHANSPEC_BW_20) {
566 chspec_ch = ctl_ch;
567 chspec_sb = 0;
568 }
569
570 else if (chspec_bw != WL_CHANSPEC_BW_8080) {
571
572 const uint8 *center_ch = NULL;
573 int num_ch = 0;
574 int sb = -1;
575
576 if (chspec_bw == WL_CHANSPEC_BW_40) {
577 center_ch = wf_5g_40m_chans;
578 num_ch = WF_NUM_5G_40M_CHANS;
579 } else if (chspec_bw == WL_CHANSPEC_BW_80) {
580 center_ch = wf_5g_80m_chans;
581 num_ch = WF_NUM_5G_80M_CHANS;
582 } else if (chspec_bw == WL_CHANSPEC_BW_160) {
583 center_ch = wf_5g_160m_chans;
584 num_ch = WF_NUM_5G_160M_CHANS;
585 } else {
586 return 0;
587 }
588
589 for (i = 0; i < num_ch; i ++) {
590 sb = channel_to_sb(center_ch[i], ctl_ch, bw);
591 if (sb >= 0) {
592 chspec_ch = center_ch[i];
593 chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
594 break;
595 }
596 }
597
598
599 if (sb < 0) {
600 return 0;
601 }
602 }
603
604 else {
605 int ch1_id = 0, ch2_id = 0;
606 int sb;
607
608 ch1_id = channel_80mhz_to_id(ch1);
609 ch2_id = channel_80mhz_to_id(ch2);
610
611
612 if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0)
613 return 0;
614
615
616 chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
617 ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
618
619
620
621
622 sb = channel_to_sb(ch1, ctl_ch, bw);
623 if (sb < 0) {
624
625 sb = channel_to_sb(ch2, ctl_ch, bw);
626 if (sb < 0) {
627
628 return 0;
629 }
630
631 sb += 4;
632 }
633
634 chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT;
635 }
636
637 chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb);
638
639 if (wf_chspec_malformed(chspec))
640 return 0;
641
642 return chspec;
643}
644
645
646bool
647wf_chspec_malformed(chanspec_t chanspec)
648{
649 uint chspec_bw = CHSPEC_BW(chanspec);
650 uint chspec_ch = CHSPEC_CHANNEL(chanspec);
651
652
653 if (CHSPEC_IS2G(chanspec)) {
654
655 if (chspec_bw != WL_CHANSPEC_BW_20 &&
656 chspec_bw != WL_CHANSPEC_BW_40) {
657 return TRUE;
658 }
659 } else if (CHSPEC_IS5G(chanspec)) {
660 if (chspec_bw == WL_CHANSPEC_BW_8080) {
661 uint ch1_id, ch2_id;
662
663
664 ch1_id = CHSPEC_CHAN1(chanspec);
665 ch2_id = CHSPEC_CHAN2(chanspec);
666 if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
667 return TRUE;
668
669
670 if (ch2_id <= ch1_id)
671 return TRUE;
672 } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
673 chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
674
675 if (chspec_ch > MAXCHANNEL) {
676 return TRUE;
677 }
678 } else {
679
680 return TRUE;
681 }
682 } else {
683
684 return TRUE;
685 }
686
687
688 if (chspec_bw == WL_CHANSPEC_BW_20) {
689 if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL)
690 return TRUE;
691 } else if (chspec_bw == WL_CHANSPEC_BW_40) {
692 if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU)
693 return TRUE;
694 } else if (chspec_bw == WL_CHANSPEC_BW_80) {
695 if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
696 return TRUE;
697 }
698
699 return FALSE;
700}
701
702
703bool
704wf_chspec_valid(chanspec_t chanspec)
705{
706 uint chspec_bw = CHSPEC_BW(chanspec);
707 uint chspec_ch = CHSPEC_CHANNEL(chanspec);
708
709 if (wf_chspec_malformed(chanspec))
710 return FALSE;
711
712 if (CHSPEC_IS2G(chanspec)) {
713
714 if (chspec_bw == WL_CHANSPEC_BW_20) {
715 if (chspec_ch >= 1 && chspec_ch <= 14)
716 return TRUE;
717 } else if (chspec_bw == WL_CHANSPEC_BW_40) {
718 if (chspec_ch >= 3 && chspec_ch <= 11)
719 return TRUE;
720 }
721 } else if (CHSPEC_IS5G(chanspec)) {
722 if (chspec_bw == WL_CHANSPEC_BW_8080) {
723 uint16 ch1, ch2;
724
725 ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)];
726 ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)];
727
728
729 if (ch2 > ch1 + CH_80MHZ_APART)
730 return TRUE;
731 } else {
732 const uint8 *center_ch;
733 uint num_ch, i;
734
735 if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) {
736 center_ch = wf_5g_40m_chans;
737 num_ch = WF_NUM_5G_40M_CHANS;
738 } else if (chspec_bw == WL_CHANSPEC_BW_80) {
739 center_ch = wf_5g_80m_chans;
740 num_ch = WF_NUM_5G_80M_CHANS;
741 } else if (chspec_bw == WL_CHANSPEC_BW_160) {
742 center_ch = wf_5g_160m_chans;
743 num_ch = WF_NUM_5G_160M_CHANS;
744 } else {
745
746 return FALSE;
747 }
748
749
750 if (chspec_bw == WL_CHANSPEC_BW_20) {
751
752 for (i = 0; i < num_ch; i ++) {
753 if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) ||
754 chspec_ch == (uint)UPPER_20_SB(center_ch[i]))
755 break;
756 }
757
758 if (i == num_ch) {
759
760 if (chspec_ch == 34 || chspec_ch == 38 ||
761 chspec_ch == 42 || chspec_ch == 46)
762 i = 0;
763 }
764 } else {
765
766 for (i = 0; i < num_ch; i ++) {
767 if (chspec_ch == center_ch[i])
768 break;
769 }
770 }
771
772 if (i < num_ch) {
773
774 return TRUE;
775 }
776 }
777 }
778
779 return FALSE;
780}
781
782
783uint8
784wf_chspec_ctlchan(chanspec_t chspec)
785{
786 uint center_chan;
787 uint bw_mhz;
788 uint sb;
789
790 ASSERT(!wf_chspec_malformed(chspec));
791
792
793 if (CHSPEC_IS20(chspec)) {
794 return CHSPEC_CHANNEL(chspec);
795 } else {
796 sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
797
798 if (CHSPEC_IS8080(chspec)) {
799 bw_mhz = 80;
800
801 if (sb < 4) {
802 center_chan = CHSPEC_CHAN1(chspec);
803 }
804 else {
805 center_chan = CHSPEC_CHAN2(chspec);
806 sb -= 4;
807 }
808
809
810 center_chan = wf_5g_80m_chans[center_chan];
811 }
812 else {
813 bw_mhz = bw_chspec_to_mhz(chspec);
814 center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT;
815 }
816
817 return (channel_to_ctl_chan(center_chan, bw_mhz, sb));
818 }
819}
820
821
822chanspec_t
823wf_chspec_ctlchspec(chanspec_t chspec)
824{
825 chanspec_t ctl_chspec = chspec;
826 uint8 ctl_chan;
827
828 ASSERT(!wf_chspec_malformed(chspec));
829
830
831 if (!CHSPEC_IS20(chspec)) {
832 ctl_chan = wf_chspec_ctlchan(chspec);
833 ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20;
834 ctl_chspec |= CHSPEC_BAND(chspec);
835 }
836 return ctl_chspec;
837}
838
839#endif
840
841
842extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
843{
844 chanspec_t chspec40 = chspec;
845 uint center_chan;
846 uint sb;
847
848 ASSERT(!wf_chspec_malformed(chspec));
849
850 if (CHSPEC_IS80(chspec)) {
851 center_chan = CHSPEC_CHANNEL(chspec);
852 sb = CHSPEC_CTL_SB(chspec);
853
854 if (sb == WL_CHANSPEC_CTL_SB_UL) {
855
856 sb = WL_CHANSPEC_CTL_SB_L;
857 center_chan += CH_20MHZ_APART;
858 } else if (sb == WL_CHANSPEC_CTL_SB_UU) {
859
860 sb = WL_CHANSPEC_CTL_SB_U;
861 center_chan += CH_20MHZ_APART;
862 } else {
863
864
865 center_chan -= CH_20MHZ_APART;
866 }
867
868
869 chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
870 sb | center_chan);
871 }
872
873 return chspec40;
874}
875
Dmitry Shmidt66eb9fa2011-05-24 11:14:33 -0700876
877int
878wf_mhz2channel(uint freq, uint start_factor)
879{
880 int ch = -1;
881 uint base;
882 int offset;
883
884
885 if (start_factor == 0) {
886 if (freq >= 2400 && freq <= 2500)
887 start_factor = WF_CHAN_FACTOR_2_4_G;
888 else if (freq >= 5000 && freq <= 6000)
889 start_factor = WF_CHAN_FACTOR_5_G;
890 }
891
892 if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
893 return 14;
894
895 base = start_factor / 2;
896
897
898 if ((freq < base) || (freq > base + 1000))
899 return -1;
900
901 offset = freq - base;
902 ch = offset / 5;
903
904
905 if (offset != (ch * 5))
906 return -1;
907
908
909 if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
910 return -1;
911
912 return ch;
913}
914
915
916int
917wf_channel2mhz(uint ch, uint start_factor)
918{
919 int freq;
920
921 if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
922 (ch > 200))
923 freq = -1;
924 else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
925 freq = 2484;
926 else
927 freq = ch * 5 + start_factor / 2;
928
929 return freq;
930}