upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / net / wireless / bcm4330 / src / shared / bcm_app_utils.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 (C) 1999-2011, Broadcom Corporation
7  * 
8  *         Unless you and Broadcom execute a separate written software license
9  * 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.
25  * $Id: bcm_app_utils.c,v 1.5 2009-12-03 23:24:26 $
26  */
27
28 #include <typedefs.h>
29
30 #ifdef BCMDRIVER
31 #include <osl.h>
32 #include <bcmutils.h>
33 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
34 #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
35 #else /* BCMDRIVER */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39 #ifndef ASSERT
40 #define ASSERT(exp)
41 #endif
42 #endif /* BCMDRIVER */
43 #include <bcmwifi.h>
44
45 #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
46 #include <bcmstdlib.h>  /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
47 #endif
48
49 #include <bcmutils.h>
50 #include <wlioctl.h>
51
52 cca_congest_channel_req_t *
53 cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg,
54         bool percent);
55
56 int
57 cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer);
58
59 /*      Take an array of measurments representing a single channel over time and return
60         a summary. Currently implemented as a simple average but could easily evolve
61         into more cpomplex alogrithms.
62 */
63 cca_congest_channel_req_t *
64 cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent)
65 {
66         int sec;
67         cca_congest_t totals;
68
69         totals.duration  = 0;
70         totals.congest_ibss  = 0;
71         totals.congest_obss  = 0;
72         totals.interference  = 0;
73         avg->num_secs = 0;
74
75         for (sec = 0; sec < input->num_secs; sec++) {
76                 if (input->secs[sec].duration) {
77                         totals.duration += input->secs[sec].duration;
78                         totals.congest_ibss += input->secs[sec].congest_ibss;
79                         totals.congest_obss += input->secs[sec].congest_obss;
80                         totals.interference += input->secs[sec].interference;
81                         avg->num_secs++;
82                 }
83         }
84         avg->chanspec = input->chanspec;
85
86         if (!avg->num_secs || !totals.duration)
87                 return (avg);
88
89         if (percent) {
90                 avg->secs[0].duration = totals.duration / avg->num_secs;
91                 avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration;
92                 avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration;
93                 avg->secs[0].interference = totals.interference * 100/totals.duration;
94         } else {
95                 avg->secs[0].duration = totals.duration / avg->num_secs;
96                 avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs;
97                 avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs;
98                 avg->secs[0].interference = totals.interference / avg->num_secs;
99         }
100
101         return (avg);
102 }
103
104 static void
105 cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos)
106 {
107         int i;
108         for (*left = 0, i = 0; i < num_bits; i++) {
109                 if (isset(bitmap, i)) {
110                         (*left)++;
111                         *bit_pos = i;
112                 }
113         }
114 }
115
116 static uint8
117 spec_to_chan(chanspec_t chspec)
118 {
119         switch (CHSPEC_CTL_SB(chspec)) {
120                 case WL_CHANSPEC_CTL_SB_NONE:
121                         return CHSPEC_CHANNEL(chspec);
122                 case WL_CHANSPEC_CTL_SB_UPPER:
123                         return UPPER_20_SB(CHSPEC_CHANNEL(chspec));
124                 case WL_CHANSPEC_CTL_SB_LOWER:
125                         return LOWER_20_SB(CHSPEC_CHANNEL(chspec));
126                 default:
127                         return 0;
128         }
129 }
130
131 #define CCA_THRESH_MILLI        14
132 #define CCA_THRESH_INTERFERE    6
133
134 /*
135         Take an array of measumrements representing summaries of different channels.
136         Return a recomended channel.
137         Interference is evil, get rid of that first.
138         Then hunt for lowest Other bss traffic.
139         Don't forget that channels with low duration times may not have accurate readings.
140         For the moment, do not overwrite input array.
141 */
142 int
143 cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer)
144 {
145         uint8 bitmap[CEIL(MAX_CCA_CHANNELS, NBBY)];     /* 38 Max channels needs 5 bytes  = 40 */
146         int i, left, winner;
147         uint32 min_obss = 1 << 30;
148
149         ASSERT(num_chans < MAX_CCA_CHANNELS);
150         for (i = 0; i < (int)sizeof(bitmap); i++)
151                 bitmap[i] = 0;
152
153         /* Initially, all channels are up for consideration */
154         for (i = 0; i < num_chans; i++) {
155                 if (input[i]->chanspec)
156                         setbit(bitmap, i);
157         }
158         cca_info(bitmap, num_chans, &left, &i);
159         if (!left)
160                 return CCA_ERRNO_TOO_FEW;
161
162         /* Filter for 2.4 GHz Band */
163         if (flags & CCA_FLAG_2G_ONLY) {
164                 for (i = 0; i < num_chans; i++) {
165                         if (!CHSPEC_IS2G(input[i]->chanspec))
166                                 clrbit(bitmap, i);
167                 }
168         }
169         cca_info(bitmap, num_chans, &left, &i);
170         if (!left)
171                 return CCA_ERRNO_BAND;
172
173         /* Filter for 5 GHz Band */
174         if (flags & CCA_FLAG_5G_ONLY) {
175                 for (i = 0; i < num_chans; i++) {
176                         if (!CHSPEC_IS5G(input[i]->chanspec))
177                                 clrbit(bitmap, i);
178                 }
179         }
180         cca_info(bitmap, num_chans, &left, &i);
181         if (!left)
182                 return CCA_ERRNO_BAND;
183
184         /* Filter for Duration */
185         if (!(flags & CCA_FLAG_IGNORE_DURATION)) {
186                 for (i = 0; i < num_chans; i++) {
187                         if (input[i]->secs[0].duration < CCA_THRESH_MILLI)
188                                 clrbit(bitmap, i);
189                 }
190         }
191         cca_info(bitmap, num_chans, &left, &i);
192         if (!left)
193                 return CCA_ERRNO_DURATION;
194
195         /* Filter for 1 6 11 on 2.4 Band */
196         if (flags &  CCA_FLAGS_PREFER_1_6_11) {
197                 int tmp_channel = spec_to_chan(input[i]->chanspec);
198                 int is2g = CHSPEC_IS2G(input[i]->chanspec);
199                 for (i = 0; i < num_chans; i++) {
200                         if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11)
201                                 clrbit(bitmap, i);
202                 }
203         }
204         cca_info(bitmap, num_chans, &left, &i);
205         if (!left)
206                 return CCA_ERRNO_PREF_CHAN;
207
208         /* Toss high interference interference */
209         if (!(flags & CCA_FLAG_IGNORE_INTERFER)) {
210                 for (i = 0; i < num_chans; i++) {
211                         if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE)
212                                 clrbit(bitmap, i);
213                 }
214                 cca_info(bitmap, num_chans, &left, &i);
215                 if (!left)
216                         return CCA_ERRNO_INTERFER;
217         }
218
219         /* Now find lowest obss */
220         winner = 0;
221         for (i = 0; i < num_chans; i++) {
222                 if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) {
223                         winner = i;
224                         min_obss = input[i]->secs[0].congest_obss;
225                 }
226         }
227         *answer = input[winner]->chanspec;
228
229         return 0;
230 }