Search Linux Wireless

[RFC] wireless: Add channel/frequency conversions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



While refactorring orinoco I found I was encapsulating the static
channel frequency table. A quick poll of drivers showed that a number of
the older driver have their own version of the table, and use it in the
same way. So rather than keep this to orinoco I added the function to
the ieee80211 header.

To be complete I've added conversion routines for all the
bands/modulations in IEEE 802.11-2007

Does this seem reasonable? Should they go somewhere else?


Thanks,

Dave.

---
Added mappings for FHSS, DSSS and OFDM channels - with macros to point
HR DSSS and ERP to the DSSS mappings. Currently just static inline
functions.

Use them in the older fullmac drivers. This eliminates a number of
const static buffers mapping channels to frequencies.

This duplicates some of the functionality exported by the cfg80211
specific net/wireless.h

Signed-off-by: David Kilroy <kilroyd@xxxxxxxxxxxxxx>
---
 drivers/net/wireless/airo.c            |   26 +++-----
 drivers/net/wireless/atmel.c           |   13 +---
 drivers/net/wireless/orinoco/orinoco.c |   34 ++++------
 drivers/net/wireless/rndis_wlan.c      |   15 ++---
 drivers/net/wireless/wl3501_cs.c       |   11 +--
 drivers/net/wireless/zd1201.c          |    7 +-
 include/linux/ieee80211.h              |  112 ++++++++++++++++++++++++++++++++
 7 files changed, 151 insertions(+), 67 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 45f8384..967b43a 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1070,10 +1070,6 @@ static WifiCtlHdr wifictlhdr8023 = {
 	}
 };
 
-// Frequency list (map channels to frequencies)
-static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
-
 // A few details needed for WEP (Wireless Equivalent Privacy)
 #define MAX_KEY_SIZE 13			// 128 (?) bits
 #define MIN_KEY_SIZE  5			// 40 bits RC4 - WEP
@@ -5739,12 +5735,10 @@ static int airo_set_freq(struct net_device *dev,
 	   (fwrq->m >= (int) 2.412e8) &&
 	   (fwrq->m <= (int) 2.487e8)) {
 		int f = fwrq->m / 100000;
-		int c = 0;
-		while((c < 14) && (f != frequency_list[c]))
-			c++;
+
 		/* Hack to fall through... */
 		fwrq->e = 0;
-		fwrq->m = c + 1;
+		fwrq->m = ieee80211_freq_to_dsss_chan(f);
 	}
 	/* Setting by channel number */
 	if((fwrq->m > 1000) || (fwrq->e > 0))
@@ -5788,8 +5782,8 @@ static int airo_get_freq(struct net_device *dev,
 
 	ch = le16_to_cpu(status_rid.channel);
 	if((ch > 0) && (ch < 15)) {
-		fwrq->m = frequency_list[ch - 1] * 100000;
-		fwrq->e = 1;
+		fwrq->m = ieee80211_dsss_chan_to_freq(ch);
+		fwrq->e = 6;
 	} else {
 		fwrq->m = ch;
 		fwrq->e = 0;
@@ -6805,8 +6799,8 @@ static int airo_get_range(struct net_device *dev,
 	k = 0;
 	for(i = 0; i < 14; i++) {
 		range->freq[k].i = i + 1; /* List index */
-		range->freq[k].m = frequency_list[i] * 100000;
-		range->freq[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
+		range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1);
+		range->freq[k++].e = 6;	/* Values in MHz -> * 10^6 */
 	}
 	range->num_frequency = k;
 
@@ -7199,11 +7193,9 @@ static inline char *airo_translate_scan(struct net_device *dev,
 	/* Add frequency */
 	iwe.cmd = SIOCGIWFREQ;
 	iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
-	/* iwe.u.freq.m containt the channel (starting 1), our 
-	 * frequency_list array start at index 0...
-	 */
-	iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000;
-	iwe.u.freq.e = 1;
+	/* iwe.u.freq.m contains the channel (starting 1) */
+	iwe.u.freq.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m);
+	iwe.u.freq.e = 6;
 	current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 					  &iwe, IW_EV_FREQ_LEN);
 
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index f551ec0..05fa951 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -2207,9 +2207,6 @@ static int atmel_get_frag(struct net_device *dev,
 	return 0;
 }
 
-static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
-
 static int atmel_set_freq(struct net_device *dev,
 			  struct iw_request_info *info,
 			  struct iw_freq *fwrq,
@@ -2223,12 +2220,10 @@ static int atmel_set_freq(struct net_device *dev,
 	    (fwrq->m >= (int) 241200000) &&
 	    (fwrq->m <= (int) 248700000)) {
 		int f = fwrq->m / 100000;
-		int c = 0;
-		while ((c < 14) && (f != frequency_list[c]))
-			c++;
+
 		/* Hack to fall through... */
 		fwrq->e = 0;
-		fwrq->m = c + 1;
+		fwrq->m = ieee80211_freq_to_dsss_chan(f);
 	}
 	/* Setting by channel number */
 	if ((fwrq->m > 1000) || (fwrq->e > 0))
@@ -2387,8 +2382,8 @@ static int atmel_get_range(struct net_device *dev,
 	if (range->num_channels != 0) {
 		for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) {
 			range->freq[k].i = i; /* List index */
-			range->freq[k].m = frequency_list[i - 1] * 100000;
-			range->freq[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
+			range->freq[k].m = ieee80211_dsss_chan_to_freq(i);
+			range->freq[k++].e = 6;	/* Values in MHz -> * 10^6 */
 		}
 		range->num_frequency = k;
 	}
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
index b33e13f..51b9812 100644
--- a/drivers/net/wireless/orinoco/orinoco.c
+++ b/drivers/net/wireless/orinoco/orinoco.c
@@ -178,12 +178,7 @@ static const struct ethtool_ops orinoco_ethtool_ops;
 /* Data tables                                                      */
 /********************************************************************/
 
-/* The frequency of each channel in MHz */
-static const long channel_frequency[] = {
-	2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-#define NUM_CHANNELS ARRAY_SIZE(channel_frequency)
+#define NUM_CHANNELS 14
 
 /* This tables gives the actual meanings of the bitrate IDs returned
  * by the firmware. */
@@ -3724,7 +3719,7 @@ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 	return err;       
 }
 
-static long orinoco_hw_get_freq(struct orinoco_private *priv)
+static int orinoco_hw_get_freq(struct orinoco_private *priv)
 {
 	
 	hermes_t *hw = &priv->hw;
@@ -3753,7 +3748,7 @@ static long orinoco_hw_get_freq(struct orinoco_private *priv)
 		goto out;
 
 	}
-	freq = channel_frequency[channel-1] * 100000;
+	freq = ieee80211_dsss_chan_to_freq(channel);
 
  out:
 	orinoco_unlock(priv, &flags);
@@ -3980,8 +3975,8 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev,
 	for (i = 0; i < NUM_CHANNELS; i++) {
 		if (priv->channel_mask & (1 << i)) {
 			range->freq[k].i = i + 1;
-			range->freq[k].m = channel_frequency[i] * 100000;
-			range->freq[k].e = 1;
+			range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1);
+			range->freq[k].e = 6;
 			k++;
 		}
 		
@@ -4329,15 +4324,14 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
 		chan = frq->m;
 	} else {
 		/* Setting by frequency - search the table */
-		int mult = 1;
+		int denom = 1;
 		int i;
 
+		/* Calculate denominator to rescale to MHz */
 		for (i = 0; i < (6 - frq->e); i++)
-			mult *= 10;
+			denom *= 10;
 
-		for (i = 0; i < NUM_CHANNELS; i++)
-			if (frq->m == (channel_frequency[i] * mult))
-				chan = i+1;
+		chan = ieee80211_freq_to_dsss_chan(frq->m / denom);
 	}
 
 	if ( (chan < 1) || (chan > NUM_CHANNELS) ||
@@ -4375,7 +4369,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
 	}
 
 	frq->m = tmp;
-	frq->e = 1;
+	frq->e = 6;
 
 	return 0;
 }
@@ -5595,8 +5589,8 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
 		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 						  &iwe, IW_EV_FREQ_LEN);
 
-		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-		iwe.u.freq.e = 1;
+		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel);
+		iwe.u.freq.e = 6;
 		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 						  &iwe, IW_EV_FREQ_LEN);
 	}
@@ -5746,8 +5740,8 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
 		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 						  &iwe, IW_EV_FREQ_LEN);
 
-		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-		iwe.u.freq.e = 1;
+		iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel);
+		iwe.u.freq.e = 6;
 		current_ev = iwe_stream_add_event(info, current_ev, end_buf,
 						  &iwe, IW_EV_FREQ_LEN);
 	}
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index ed5785a..7b0f0f5 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -369,9 +369,6 @@ struct rndis_wext_private {
 };
 
 
-static const int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
-
 static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 };
 
 static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
@@ -640,8 +637,8 @@ static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq)
 static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
 {
 	if (freq->m < 1000 && freq->e == 0) {
-		if (freq->m >= 1 && freq->m <= ARRAY_SIZE(freq_chan))
-			*dsconfig = freq_chan[freq->m - 1] * 1000;
+		if (freq->m >= 1 && freq->m <= 14)
+			*dsconfig = ieee80211_dsss_chan_to_freq(freq->m) * 1000;
 		else
 			return -1;
 	} else {
@@ -1178,12 +1175,12 @@ static int rndis_iw_get_range(struct net_device *dev,
 		range->throughput = 11 * 1000 * 1000 / 2;
 	}
 
-	range->num_channels = ARRAY_SIZE(freq_chan);
+	range->num_channels = 14;
 
-	for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) {
+	for (i = 0; (i < 14) && (i < IW_MAX_FREQUENCIES); i++) {
 		range->freq[i].i = i + 1;
-		range->freq[i].m = freq_chan[i] * 100000;
-		range->freq[i].e = 1;
+		range->freq[i].m = ieee80211_dsss_chan_to_freq(i + 1);
+		range->freq[i].e = 6;
 	}
 	range->num_frequency = i;
 
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 68789c6..7c17c40 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 
 #include <net/iw_handler.h>
 
@@ -111,12 +112,6 @@ static void wl3501_release(struct pcmcia_device *link);
  */
 static dev_info_t wl3501_dev_info = "wl3501_cs";
 
-static int wl3501_chan2freq[] = {
-	[0]  = 2412, [1]  = 2417, [2]  = 2422, [3]  = 2427, [4] = 2432,
-	[5]  = 2437, [6]  = 2442, [7]  = 2447, [8]  = 2452, [9] = 2457,
-	[10] = 2462, [11] = 2467, [12] = 2472, [13] = 2477,
-};
-
 static const struct {
 	int reg_domain;
 	int min, max, deflt;
@@ -1512,8 +1507,8 @@ static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
 {
 	struct wl3501_card *this = netdev_priv(dev);
 
-	wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000;
-	wrqu->freq.e = 1;
+	wrqu->freq.m = ieee80211_dsss_chan_to_freq(this->chan);
+	wrqu->freq.e = 6;
 	return 0;
 }
 
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 45a5747..59e00eb 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -921,10 +921,9 @@ static int zd1201_set_freq(struct net_device *dev,
 	if (freq->e == 0)
 		channel = freq->m;
 	else {
-		if (freq->m >= 2482)
-			channel = 14;
-		if (freq->m >= 2407)
-			channel = (freq->m-2407)/5;
+		channel = ieee80211_freq_to_dsss_chan(freq->m);
+		if (channel < 0)
+			channel = 0;
 	}
 
 	err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index c4e6ca1..c530e89 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1185,4 +1185,116 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
 		return hdr->addr1;
 }
 
+/**
+ * ieee80211_fhss_chan_to_freq - get channel frequency
+ * @channel: the FHSS channel
+ *
+ * Convert IEEE802.11 FHSS channel to frequency (MHz)
+ * Ref IEEE 802.11-2007 section 14.6
+ */
+static inline int ieee80211_fhss_chan_to_freq(int channel)
+{
+	if ((channel > 1) && (channel < 96))
+		return channel + 2400;
+	else
+		return -1;
+}
+
+/**
+ * ieee80211_freq_to_fhss_chan - get channel
+ * @freq: the channels frequency
+ *
+ * Convert frequency (MHz) to IEEE802.11 FHSS channel
+ * Ref IEEE 802.11-2007 section 14.6
+ */
+static inline int ieee80211_freq_to_fhss_chan(int freq)
+{
+	if ((freq > 2401) && (freq < 2496))
+		return freq - 2400;
+	else
+		return -1;
+}
+
+/**
+ * ieee80211_dsss_chan_to_freq - get channel frequency
+ * @channel: the DSSS channel
+ *
+ * Convert IEEE802.11 DSSS channel to frequency (MHz)
+ * Ref IEEE 802.11-2007 section 15.6
+ */
+static inline int ieee80211_dsss_chan_to_freq(int channel)
+{
+	if ((channel > 0) && (channel < 14))
+		return 2407 + (channel * 5);
+	else if (channel == 14)
+		return 2484;
+	else
+		return -1;
+}
+
+/**
+ * ieee80211_freq_to_dsss_chan - get channel
+ * @freq: the channels frequency
+ *
+ * Convert frequency (MHz) to IEEE802.11 DSSS channel
+ * Ref IEEE 802.11-2007 section 15.6
+ */
+static inline int ieee80211_freq_to_dsss_chan(int freq)
+{
+	if ((freq > 2407) && (freq < 2477))
+		return (freq - 2407) / 5;
+	else if (freq == 2484)
+		return 14;
+	else
+		return -1;
+}
+
+/* Convert IEEE802.11 HR DSSS channel to frequency (MHz) and back
+ * Ref IEEE 802.11-2007 section 18.4.6.2
+ *
+ * The channels and frequencies are the same as those defined for DSSS
+ */
+#define ieee80211_hr_chan_to_freq(chan) ieee80211_dsss_chan_to_freq(chan)
+#define ieee80211_freq_to_hr_chan(freq) ieee80211_freq_to_dsss_chan(freq)
+
+/* Convert IEEE802.11 ERP channel to frequency (MHz) and back
+ * Ref IEEE 802.11-2007 section 19.4.2
+ */
+#define ieee80211_erp_chan_to_freq(chan) ieee80211_hr_chan_to_freq(chan)
+#define ieee80211_freq_to_erp_chan(freq) ieee80211_freq_to_hr_chan(freq)
+
+/**
+ * ieee80211_ofdm_chan_to_freq - get channel frequency
+ * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
+ * @channel: the OFDM channel
+ *
+ * Convert IEEE802.11 OFDM channel to frequency (MHz)
+ * Ref IEEE 802.11-2007 section 17.3.8.3.2
+ */
+static inline int ieee80211_ofdm_chan_to_freq(int s_freq, int channel)
+{
+	if ((channel > 0) && (channel <= 200) &&
+	    (s_freq >= 4000))
+		return s_freq + (channel * 5);
+	else
+		return -1;
+}
+
+/**
+ * ieee80211_freq_to_ofdm_channel - get channel
+ * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
+ * @freq: the channels frequency
+ *
+ * Convert frequency (MHz) to IEEE802.11 OFDM channel
+ * Ref IEEE 802.11-2007 section 17.3.8.3.2
+ */
+static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
+{
+	if ((freq > s_freq) && (freq <= (s_freq + 1200)) &&
+	    (s_freq >= 4000))
+		return (freq - s_freq) / 5;
+	else
+		return -1;
+}
+
 #endif /* LINUX_IEEE80211_H */
-- 
1.5.6.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux