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 2007, 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: bcmwifi.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $
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 */
49char *
50wf_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
79chanspec_t
80wf_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}
155
156#ifdef CONFIG_NET_RADIO
157/* channel info structure */
158typedef struct {
159	uint	chan;		/* channel number */
160	uint	freq;		/* in Mhz */
161} chan_info_t;
162
163static chan_info_t chan_info[] = {
164	/* B channels */
165	{ 1,	2412},
166	{ 2,	2417},
167	{ 3,	2422},
168	{ 4,	2427},
169	{ 5,	2432},
170	{ 6,	2437},
171	{ 7,	2442},
172	{ 8,	2447},
173	{ 9,	2452},
174	{ 10,	2457},
175	{ 11,	2462},
176	{ 12,	2467},
177	{ 13,	2472},
178	{ 14,	2484},
179
180	/* A channels */
181	/* 11a usa low */
182	{ 36,	5180},
183	{ 40,	5200},
184	{ 44,	5220},
185	{ 48,	5240},
186	{ 52,	5260},
187	{ 56,	5280},
188	{ 60,	5300},
189	{ 64,	5320},
190
191	/* 11a Europe */
192	{ 100,	5500},
193	{ 104,	5520},
194	{ 108,	5540},
195	{ 112,	5560},
196	{ 116,	5580},
197	{ 120,	5600},
198	{ 124,	5620},
199	{ 128,	5640},
200	{ 132,	5660},
201	{ 136,	5680},
202	{ 140,	5700},
203
204	/* 11a usa high */
205	{ 149,	5745},
206	{ 153,	5765},
207	{ 157,	5785},
208	{ 161,	5805},
209
210	/* 11a japan */
211	{ 184,	4920},
212	{ 188,	4940},
213	{ 192,	4960},
214	{ 196,	4980},
215	{ 200,	5000},
216	{ 204,	5020},
217	{ 208,	5040},
218	{ 212,	5060},
219	{ 216,	5080}
220};
221
222
223uint
224freq2channel(uint freq)
225{
226	int i;
227
228	for (i = 0; i < (int)ARRAYSIZE(chan_info); i++) {
229		if (chan_info[i].freq == freq)
230			return (chan_info[i].chan);
231	}
232	return (0);
233}
234
235uint
236channel2freq(uint channel)
237{
238	uint i;
239
240	for (i = 0; i < ARRAYSIZE(chan_info); i++)
241		if (chan_info[i].chan == channel)
242			return (chan_info[i].freq);
243	return (0);
244}
245#endif /* CONFIG_NET_RADIO */
246