14d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/*
24d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * Misc utility routines used by kernel or app-level.
34d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * Contents are wifi-specific, used by any kernel or app-level
44d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * software that might want wifi things as it grows.
54d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
69984c42af1f24da360515edd81441ef5dfe23da4Dmitry Shmidt * Copyright (C) 1999-2010, Broadcom Corporation
74d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
84d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      Unless you and Broadcom execute a separate written software license
94d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * agreement governing use of this software, this software is licensed to you
104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * under the terms of the GNU General Public License version 2 (the "GPL"),
114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * available at http://www.broadcom.com/licenses/GPLv2.php, with the
124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * following added to such license:
134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      As a special exception, the copyright holders of this software give you
154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * permission to link this software with independent modules, and to copy and
164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * distribute the resulting executable under terms of your choice, provided that
174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * you also meet, for each linked independent module, the terms and conditions of
184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * the license of that module.  An independent module is a module which is not
194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * derived from this software.  The special exception does not apply to any
204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * modifications of the software.
214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      Notwithstanding the above, under no circumstances may you combine this
234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * software in any way with any other Broadcom software provided under a license
244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * other than the GPL, without Broadcom's express prior written consent.
25492884be0b302c6c6ea51b360c1f7b0996d96a8bDmitry Shmidt * $Id: bcmwifi.c,v 1.18.24.2.4.1 2009/09/25 00:32:01 Exp $
264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt */
274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <typedefs.h>
304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#ifdef BCMDRIVER
324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <osl.h>
334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmutils.h>
344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#else
374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <stdio.h>
384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <stdlib.h>
394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <ctype.h>
404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#endif
414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmwifi.h>
424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmstdlib.h>
454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#endif
464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtchar *
524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtwf_chspec_ntoa(chanspec_t chspec, char *buf)
534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	const char *band, *bw, *sb;
554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint channel;
564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	band = "";
584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bw = "";
594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sb = "";
604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	channel = CHSPEC_CHANNEL(chspec);
614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	    (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (CHSPEC_IS40(chspec)) {
664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (CHSPEC_SB_UPPER(chspec)) {
674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sb = "u";
684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			channel += CH_10MHZ_APART;
694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else {
704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sb = "l";
714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			channel -= CH_10MHZ_APART;
724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else if (CHSPEC_IS10(chspec)) {
744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bw = "n";
754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (buf);
804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtchanspec_t
844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtwf_chspec_aton(char *a)
854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
86492884be0b302c6c6ea51b360c1f7b0996d96a8bDmitry Shmidt	char *endp = NULL;
874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint channel, band, bw, ctl_sb;
884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	char c;
894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	channel = strtoul(a, &endp, 10);
914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (endp == a)
944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return 0;
954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (channel > MAXCHANNEL)
974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return 0;
984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
1004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bw = WL_CHANSPEC_BW_20;
1014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
1024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	a = endp;
1044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	c = tolower(a[0]);
1064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (c == '\0')
1074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		goto done;
1084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (c == 'a' || c == 'b') {
1114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
1124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		a++;
1134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		c = tolower(a[0]);
1144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (c == '\0')
1154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			goto done;
1164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (c == 'n') {
1204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bw = WL_CHANSPEC_BW_10;
1214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else if (c == 'l') {
1224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bw = WL_CHANSPEC_BW_40;
1234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
1244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
1264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			channel += CH_10MHZ_APART;
1274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		else
1284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return 0;
1294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else if (c == 'u') {
1304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bw = WL_CHANSPEC_BW_40;
1314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
1324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (channel > CH_20MHZ_APART)
1344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			channel -= CH_10MHZ_APART;
1354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		else
1364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return 0;
1374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else {
1384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return 0;
1394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtdone:
1424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (channel | band | bw | ctl_sb);
1434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
1474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtwf_mhz2channel(uint freq, uint start_factor)
1484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
1494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int ch = -1;
1504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint base;
1514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int offset;
1524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (start_factor == 0) {
1554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (freq >= 2400 && freq <= 2500)
1564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			start_factor = WF_CHAN_FACTOR_2_4_G;
1574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		else if (freq >= 5000 && freq <= 6000)
1584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			start_factor = WF_CHAN_FACTOR_5_G;
1594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
1624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return 14;
1634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	base = start_factor / 2;
1654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((freq < base) || (freq > base + 1000))
1684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return -1;
1694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	offset = freq - base;
1714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ch = offset / 5;
1724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (offset != (ch * 5))
1754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return -1;
1764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
1794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return -1;
1804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return ch;
1824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
1864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtwf_channel2mhz(uint ch, uint start_factor)
1874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
1884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int freq;
1894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
1914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	    (ch <= 200))
1924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		freq = -1;
1934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
1944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		freq = 2484;
1954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else
1964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		freq = ch * 5 + start_factor / 2;
1974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return freq;
1994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
200