From e12b5ec8df924138e6546c2abe3b42bf5b0a96c3 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 17 Aug 2013 13:38:30 +0000
Subject: [PATCH] broadcom-wl: Add 'N' mode support to broadcom-wl
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

This is partly based on patches sent by Łukasz Kwestarz (See https://lists.openwrt.org/pipermail/openwrt-devel/2012-March/014356.html).

Signed-off-by: Nathan Hintz <nlhintz@hotmail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

SVN-Revision: 37802
---
 package/kernel/broadcom-wl/Makefile           |  2 +-
 .../broadcom-wl/files/lib/wifi/broadcom.sh    | 44 ++++++++++++++++---
 package/kernel/broadcom-wl/src/wlc.c          | 41 +++++++++++++++--
 3 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/package/kernel/broadcom-wl/Makefile b/package/kernel/broadcom-wl/Makefile
index 1a7da0f89d..3b4d54cf28 100644
--- a/package/kernel/broadcom-wl/Makefile
+++ b/package/kernel/broadcom-wl/Makefile
@@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=broadcom-wl
 PKG_VERSION:=5.10.56.27.3
-PKG_RELEASE:=5
+PKG_RELEASE:=6
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(ARCH).tar.bz2
 PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
diff --git a/package/kernel/broadcom-wl/files/lib/wifi/broadcom.sh b/package/kernel/broadcom-wl/files/lib/wifi/broadcom.sh
index 72b85aaf88..4d81bcb1b4 100644
--- a/package/kernel/broadcom-wl/files/lib/wifi/broadcom.sh
+++ b/package/kernel/broadcom-wl/files/lib/wifi/broadcom.sh
@@ -131,6 +131,7 @@ enable_broadcom() {
 	config_get frag "$device" frag
 	config_get rts "$device" rts
 	config_get hwmode "$device" hwmode
+	config_get htmode "$device" htmode
 	local vif_pre_up vif_post_up vif_do_up vif_txpower
 	local doth=0
 	local wmm=1
@@ -161,15 +162,40 @@ enable_broadcom() {
 		;;
 	esac
 
+	[ ${channel:-0} -ge 1 -a ${channel:-0} -le 14 ] && band=2
+	[ ${channel:-0} -ge 36 ] && band=1
+
 	case "$hwmode" in
-		*b)   hwmode=0;;
-		*bg)  hwmode=1;;
-		*g)   hwmode=2;;
-		*gst) hwmode=4;;
-		*lrs) hwmode=5;;
-		*)    hwmode=1;;
+		*na)	nmode=1; nreqd=0;;
+		*a)	nmode=0;;
+		*ng)	gmode=1; nmode=1; nreqd=0;;
+		*n)	nmode=1; nreqd=1;;
+		*b)	gmode=0; nmode=0;;
+		*bg)	gmode=1; nmode=0;;
+		*g)	gmode=2; nmode=0;;
+		*gst)	gmode=4; nmode=0;;
+		*lrs)	gmode=5; nmode=0;;
+		*)      case "$band" in
+				2) gmode=1; nmode=1; nreqd=0;;
+				1) nmode=1; nreqd=0;;
+				*) gmode=1; nmode=1; nreqd=0;;
+			esac
+			;;
 	esac
 
+        # Use 'nmode' for N-Phy only
+	[ "$(wlc ifname $device phytype)" = 4 ] || nmode=
+
+	# Use 'chanspec' instead of 'channel' for 'N' modes (See bcmwifi.h)
+	[ ${nmode:-0} -ne 0 -a -n "$band" ] && {
+		case "$htmode" in
+			HT40-)	chanspec=$(printf 0x%x%x%02x $band 0xe $(($channel - 2))); channel=;;
+			HT40+)	chanspec=$(printf 0x%x%x%02x $band 0xd $(($channel + 2))); channel=;;
+			HT20)	chanspec=$(printf 0x%x%x%02x $band 0xb $channel); channel=;;
+			*) ;;
+		esac
+	}
+
 	for vif in $vifs; do
 		config_get vif_txpower "$vif" txpower
 
@@ -322,7 +348,10 @@ enable_broadcom() {
 	wlc ifname "$device" stdin <<EOF
 $ifdown
 
-gmode ${hwmode:-1}
+${nmode:+band ${band:-0}}
+${nmode:+nmode $nmode}
+${nmode:+${nreqd:+nreqd $nreqd}}
+${gmode:+gmode $gmode}
 apsta $apsta
 ap $ap
 ${mssid:+mssid $mssid}
@@ -344,6 +373,7 @@ wds none
 ${wds:+wds $wds}
 country ${country:-US}
 ${channel:+channel $channel}
+${chanspec:+chanspec $chanspec}
 maxassoc ${maxassoc:-128}
 slottime ${slottime:--1}
 ${frameburst:+frameburst $frameburst}
diff --git a/package/kernel/broadcom-wl/src/wlc.c b/package/kernel/broadcom-wl/src/wlc.c
index 253809c9a3..7e638e5c6f 100644
--- a/package/kernel/broadcom-wl/src/wlc.c
+++ b/package/kernel/broadcom-wl/src/wlc.c
@@ -499,8 +499,8 @@ static int wlc_pmk(wlc_param param, void *data, void *value)
 	/* driver doesn't support GET */
 
 	if ((param & PARAM_MODE) == SET) {
-		strncpy(pmk.key, value, WSEC_MAX_PSK_LEN);
-		pmk.key_len = strlen(value);
+		strncpy(pmk.key, str, WSEC_MAX_PSK_LEN);
+		pmk.key_len = strlen(str);
 
 		if (pmk.key_len > WSEC_MAX_PSK_LEN)
 			pmk.key_len = WSEC_MAX_PSK_LEN;
@@ -912,6 +912,41 @@ static const struct wlc_call wlc_calls[] = {
 		.handler = wlc_ioctl,
 		.desc = "G Mode"
 	},
+	{
+		.name = "phytype",
+		.param = INT,
+		.data.num = (WLC_GET_PHYTYPE << 16),
+		.handler = wlc_ioctl,
+		.desc = "PHY Type"
+	},
+	{
+		.name = "nmode",
+		.param = INT,
+		.handler = wlc_iovar,
+		.data.str = "nmode",
+		.desc = "N Mode"
+	},
+	{
+		.name = "nreqd",
+		.param = INT,
+		.handler = wlc_iovar,
+		.data.str = "nreqd",
+		.desc = "N Mode required"
+	},
+	{
+		.name = "chanspec",
+		.param = INT,
+		.handler = wlc_iovar,
+		.data.str = "chanspec",
+		.desc = "Channel Spec (See bcmwifi.h)"
+	},
+	{
+		.name = "band",
+		.param = INT,
+		.data.num = ((WLC_GET_BAND << 16) | WLC_SET_BAND),
+		.handler = wlc_ioctl,
+		.desc = "Band"
+	},
 };
 #define wlc_calls_size (sizeof(wlc_calls) / sizeof(struct wlc_call))
 
@@ -971,7 +1006,7 @@ static int do_command(const struct wlc_call *cmd, char *arg)
 		set = 1;
 		switch(cmd->param & PARAM_TYPE) {
 			case INT:
-				intval = strtoul(arg, &end, 10);
+				intval = strtoul(arg, &end, 0);
 				if (end && !(*end)) {
 					memcpy(buf, &intval, sizeof(intval));
 				} else {
-- 
2.34.1