www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / bcmdrivers / broadcom / net / wl / impl2 / shared / bcmwifi.c
1 /*
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  *
6  * Copyright 2006, Broadcom Corporation
7  * All Rights Reserved.                
8  *                                     
9  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;   
10  * the contents of this file may not be disclosed to third parties, copied
11  * or duplicated in any form, in whole or in part, without the prior      
12  * written permission of Broadcom Corporation.                            
13  * $Id$
14  */
15
16 #include <typedefs.h>
17
18 #ifdef BCMDRIVER
19 #include <osl.h>
20 #include <bcmutils.h>
21 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
22 #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
23 #else
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <ctype.h>
27 #endif /* BCMDRIVER */
28 #include <bcmwifi.h>
29
30 /* Chanspec ASCII representation:
31  * <channel><band><bandwidth><ctl-sideband>
32  *   digit   [AB]      N          [UL]
33  *
34  * <channel>: channel number of the 10MHz or 20MHz channel,
35  *      or control sideband channel of 40MHz channel.
36  * <band>: A for 5GHz, B for 2.4GHz
37  * <bandwidth>: N for 10MHz, nothing for 20MHz or 40MHz
38  *      (ctl-sideband spec implies 40MHz)
39  * <ctl-sideband>: U for upper, L for lower
40  *
41  * <band> may be omitted on input, and will be assumed to be
42  * 2.4GHz if channel number <= 14.
43  *
44  * Examples: ...
45  */
46 /* given a chanspec and a string buffer, format the chanspec as a
47  * string, and return the original pointer a. On error, return's NULL
48  */
49 char *
50 wf_chspec_ntoa(chanspec_t chspec, char *buf)
51 {
52         const char *band, *bw, *sb;
53         uint channel;
54
55         bw = "";
56         sb = "";
57         channel = CHSPEC_CHANNEL(chspec);
58         band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
59         if (CHSPEC_IS40(chspec)) {
60                 if (CHSPEC_SB_UPPER(chspec)) {
61                         sb = "u";
62                         channel += CH_10MHZ_APART;
63                 } else {
64                         sb = "l";
65                         channel -= CH_10MHZ_APART;
66                 }
67         } else if (CHSPEC_IS10(chspec)) {
68                 bw = "n";
69         }
70
71         sprintf(buf, "%d%s%s%s", channel, band, bw, sb);
72         return (buf);
73 }
74
75 /* given a chanspec string, convert to a chanspec.
76  * On error, return 0
77  */
78
79 chanspec_t
80 wf_chspec_aton(char *a)
81 {
82         char *endp;
83         uint channel, band, bw, ctl_sb;
84         bool band_set = FALSE, bw_set = FALSE, ctl_sb_set = FALSE;
85         int error = 0;
86
87         channel = strtoul(a, &endp, 10);
88         if (endp == a)
89                 return 0;
90
91         if (channel > MAXCHANNEL)
92                 return 0;
93
94         band = ((channel <= WLC_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
95         bw = WL_CHANSPEC_BW_20;
96         ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
97
98         a = endp;
99         while (*a != 0 && error != -1) {
100                 switch (tolower((int)*a)) {
101                         case 'a':
102                         case 'b':
103                                 if (!band_set) {
104                                         band = (tolower((int)*a) == 'a') ?
105                                                WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
106                                         band_set = TRUE;
107                                 } else {
108                                         error = -1;
109                                 }
110                                 break;
111                         case 'n':
112                                 if (!bw_set) {
113                                         bw = WL_CHANSPEC_BW_10;
114                                         bw_set = TRUE;
115                                 } else {
116                                         error = -1;
117                                 }
118                                 break;
119                         case 'l':
120                         case 'u':
121                                 if (!ctl_sb_set && !bw_set) {
122                                         ctl_sb = (tolower((int)*a) == 'l') ?
123                                                 WL_CHANSPEC_CTL_SB_LOWER : WL_CHANSPEC_CTL_SB_UPPER;
124                                         ctl_sb_set = TRUE;
125                                         if (ctl_sb == WL_CHANSPEC_CTL_SB_LOWER)
126                                                 channel = UPPER_20_SB(channel);
127                                         else
128                                                 channel = LOWER_20_SB(channel);
129                                         bw = WL_CHANSPEC_BW_40;
130                                         bw_set = TRUE;
131                                 } else if (bw_set) {
132                                         error = -1;
133                                 } else {
134                                         error = -1;
135                                 }
136                                 break;
137                         default:
138                                 error = -1;
139                                 break;
140                 }
141                 a++;
142         }
143
144         if (bw_set && (bw == WL_CHANSPEC_BW_40) && !ctl_sb_set)
145                 error = -1;
146
147         if (ctl_sb_set && !bw_set)
148                 error = -1;
149
150         if (!error)
151                 return ((channel | band | bw | ctl_sb));
152
153         return 0;
154 }