From e01799a285e34c65d41ac315dd29544fc40acf19 Mon Sep 17 00:00:00 2001
From: jow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Fri, 17 Feb 2012 00:36:25 +0000
Subject: [PATCH] [package] iwinfo: implement proper hardware detection for
 ar23xx SoC devices like the NanoStation 2

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@30605 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 package/iwinfo/Makefile                   |  2 +-
 package/iwinfo/src/include/iwinfo.h       |  1 +
 package/iwinfo/src/include/iwinfo/utils.h |  2 +
 package/iwinfo/src/iwinfo_madwifi.c       | 75 +----------------------
 package/iwinfo/src/iwinfo_nl80211.c       | 15 ++++-
 package/iwinfo/src/iwinfo_utils.c         | 60 ++++++++++++++++++
 6 files changed, 78 insertions(+), 77 deletions(-)

diff --git a/package/iwinfo/Makefile b/package/iwinfo/Makefile
index 27caf9fcb..35ba0cc18 100644
--- a/package/iwinfo/Makefile
+++ b/package/iwinfo/Makefile
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=libiwinfo
-PKG_RELEASE:=25
+PKG_RELEASE:=26
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 PKG_CONFIG_DEPENDS := \
diff --git a/package/iwinfo/src/include/iwinfo.h b/package/iwinfo/src/include/iwinfo.h
index 198d57c9d..40b85a049 100644
--- a/package/iwinfo/src/include/iwinfo.h
+++ b/package/iwinfo/src/include/iwinfo.h
@@ -15,6 +15,7 @@
 #include <stdint.h>
 
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <net/if.h>
 #include <errno.h>
 
diff --git a/package/iwinfo/src/include/iwinfo/utils.h b/package/iwinfo/src/include/iwinfo/utils.h
index e897b2718..10246a8e3 100644
--- a/package/iwinfo/src/include/iwinfo/utils.h
+++ b/package/iwinfo/src/include/iwinfo/utils.h
@@ -39,4 +39,6 @@ void iwinfo_close(void);
 
 struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id);
 
+int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id);
+
 #endif
diff --git a/package/iwinfo/src/iwinfo_madwifi.c b/package/iwinfo/src/iwinfo_madwifi.c
index 732cfe56f..fcd6c8c98 100644
--- a/package/iwinfo/src/iwinfo_madwifi.c
+++ b/package/iwinfo/src/iwinfo_madwifi.c
@@ -988,40 +988,6 @@ int madwifi_get_mbssid_support(const char *ifname, int *buf)
 	return -1;
 }
 
-static void madwifi_proc_file(const char *ifname, const char *file,
-							  char *buf, int blen)
-{
-	int fd;
-	const char *wifi = madwifi_isvap(ifname, NULL);
-
-	if (!wifi && madwifi_iswifi(ifname))
-		wifi = ifname;
-
-	snprintf(buf, blen, "/proc/sys/dev/%s/%s", wifi, file);
-
-	if ((fd = open(buf, O_RDONLY)) > 0)
-	{
-		if (read(fd, buf, blen) > 1)
-			buf[strlen(buf)-1] = 0;
-		else
-			buf[0] = 0;
-
-		close(fd);
-	}
-	else
-	{
-		buf[0] = 0;
-	}
-}
-
-static int madwifi_startswith(const char *a, const char *b)
-{
-	int l1 = strlen(a);
-	int l2 = strlen(b);
-	int ln = (l1 < l2) ? l1 : l2;
-	return !strncmp(a, b, ln);
-}
-
 int madwifi_get_hardware_id(const char *ifname, char *buf)
 {
 	char vendor[64];
@@ -1030,32 +996,7 @@ int madwifi_get_hardware_id(const char *ifname, char *buf)
 	struct iwinfo_hardware_entry *e;
 
 	if (wext_get_hardware_id(ifname, buf))
-	{
-		ids = (struct iwinfo_hardware_id *)buf;
-		madwifi_proc_file(ifname, "dev_vendor", vendor, sizeof(vendor));
-		madwifi_proc_file(ifname, "dev_name",   device, sizeof(device));
-
-		if (vendor[0] && device[0])
-		{
-			for (e = IWINFO_HARDWARE_ENTRIES; e->vendor_name; e++)
-			{
-				if (!madwifi_startswith(vendor, e->vendor_name))
-					continue;
-
-				if (!madwifi_startswith(device, e->device_name))
-					continue;
-
-				ids->vendor_id = e->vendor_id;
-				ids->device_id = e->device_id;
-				ids->subsystem_vendor_id = e->subsystem_vendor_id;
-				ids->subsystem_device_id = e->subsystem_device_id;
-
-				return 0;
-			}
-		}
-
-		return -1;
-	}
+		return iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf);
 
 	return 0;
 }
@@ -1073,24 +1014,12 @@ madwifi_get_hardware_entry(const char *ifname)
 
 int madwifi_get_hardware_name(const char *ifname, char *buf)
 {
-	char vendor[64];
-	char device[64];
 	const struct iwinfo_hardware_entry *hw;
 
 	if (!(hw = madwifi_get_hardware_entry(ifname)))
-	{
-		madwifi_proc_file(ifname, "dev_vendor", vendor, sizeof(vendor));
-		madwifi_proc_file(ifname, "dev_name",   device, sizeof(device));
-
-		if (vendor[0] && device[0])
-			sprintf(buf, "%s %s", vendor, device);
-		else
-			sprintf(buf, "Generic Atheros");
-	}
+		sprintf(buf, "Generic Atheros");
 	else
-	{
 		sprintf(buf, "%s %s", hw->vendor_name, hw->device_name);
-	}
 
 	return 0;
 }
diff --git a/package/iwinfo/src/iwinfo_nl80211.c b/package/iwinfo/src/iwinfo_nl80211.c
index e8cfb902f..5c6f7a8ef 100644
--- a/package/iwinfo/src/iwinfo_nl80211.c
+++ b/package/iwinfo/src/iwinfo_nl80211.c
@@ -1646,7 +1646,7 @@ int nl80211_get_hardware_id(const char *ifname, char *buf)
 		/* Reuse existing interface */
 		if ((res = nl80211_phy2ifname(ifname)) != NULL)
 		{
-			return wext_get_hardware_id(res, buf);
+			rv = wext_get_hardware_id(res, buf);
 		}
 
 		/* Need to spawn a temporary iface for finding IDs */
@@ -1654,11 +1654,20 @@ int nl80211_get_hardware_id(const char *ifname, char *buf)
 		{
 			rv = wext_get_hardware_id(res, buf);
 			nl80211_ifdel(res);
-			return rv;
 		}
 	}
+	else
+	{
+		rv = wext_get_hardware_id(ifname, buf);
+	}
 
-	return wext_get_hardware_id(ifname, buf);
+	/* Failed to obtain hardware IDs, search board config */
+	if (rv)
+	{
+		rv = iwinfo_hardware_id_from_mtd(buf);
+	}
+
+	return rv;
 }
 
 static const struct iwinfo_hardware_entry *
diff --git a/package/iwinfo/src/iwinfo_utils.c b/package/iwinfo/src/iwinfo_utils.c
index b49447b07..ec6aa2233 100644
--- a/package/iwinfo/src/iwinfo_utils.c
+++ b/package/iwinfo/src/iwinfo_utils.c
@@ -150,3 +150,63 @@ struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id)
 
 	return NULL;
 }
+
+int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id)
+{
+	FILE *mtd;
+	uint16_t *bc;
+
+	int fd, len, off;
+	char buf[128];
+
+	if (!(mtd = fopen("/proc/mtd", "r")))
+		return -1;
+
+	while (fgets(buf, sizeof(buf), mtd) > 0)
+	{
+		if (fscanf(mtd, "mtd%d: %*x %x %127s", &off, &len, buf) < 3 ||
+		    strcmp(buf, "\"boardconfig\""))
+		{
+			off = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	fclose(mtd);
+
+	if (off < 0)
+		return -1;
+
+	snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off);
+
+	if ((fd = open(buf, O_RDONLY)) < 0)
+		return -1;
+
+	bc = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_LOCKED, fd, 0);
+
+	if ((void *)bc != MAP_FAILED)
+	{
+		id->vendor_id = 0;
+		id->device_id = 0;
+
+		for (off = len / 2 - 0x800; off >= 0; off -= 0x800)
+		{
+			if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131))
+			{
+				id->vendor_id = bc[off + 0x7d];
+				id->device_id = bc[off + 0x7c];
+				id->subsystem_vendor_id = bc[off + 0x84];
+				id->subsystem_device_id = bc[off + 0x83];
+				break;
+			}
+		}
+
+		munmap(bc, len);
+	}
+
+	close(fd);
+
+	return (id->vendor_id && id->device_id) ? 0 : -1;
+}
-- 
2.20.1