2008-12-23 14:03:47

by Dave Kilroy

[permalink] [raw]
Subject: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

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 the new functions in the older fullmac drivers. This eliminates a
number of const static buffers and removes a couple of range checks that
are now redundant.

Signed-off-by: David Kilroy <[email protected]>
---

This has changed from the RFC as follows:

- freq_to_chan conversions return the channel with the closest
center frequency (instead of rounding down)
- Remove a couple frequency checks which are now redundant
- Leaving the WE exponents alone

Also note this changes the frequency reported by wl3501 for channel 14.
I've assumed this is a fix...

---
drivers/net/wireless/airo.c | 25 ++-----
drivers/net/wireless/atmel.c | 20 ++---
drivers/net/wireless/orinoco/orinoco.c | 33 ++++-----
drivers/net/wireless/rndis_wlan.c | 13 ++--
drivers/net/wireless/wl3501_cs.c | 9 +--
drivers/net/wireless/zd1201.c | 7 +-
include/linux/ieee80211.h | 116 ++++++++++++++++++++++++++++++++
7 files changed, 155 insertions(+), 68 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 45f8384..35f28ee 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
@@ -5735,16 +5731,12 @@ static int airo_set_freq(struct net_device *dev,
int rc = -EINPROGRESS; /* Call commit handler */

/* If setting by frequency, convert to a channel */
- if((fwrq->e == 1) &&
- (fwrq->m >= (int) 2.412e8) &&
- (fwrq->m <= (int) 2.487e8)) {
+ if(fwrq->e == 1) {
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,7 +5780,7 @@ 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->m = ieee80211_dsss_chan_to_freq(ch) * 100000;
fwrq->e = 1;
} else {
fwrq->m = ch;
@@ -6805,8 +6797,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) * 100000;
+ range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
}
range->num_frequency = k;

@@ -7199,10 +7191,7 @@ 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.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000;
iwe.u.freq.e = 1;
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..28dedb8 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,
@@ -2219,16 +2216,12 @@ static int atmel_set_freq(struct net_device *dev,
int rc = -EINPROGRESS; /* Call commit handler */

/* If setting by frequency, convert to a channel */
- if ((fwrq->e == 1) &&
- (fwrq->m >= (int) 241200000) &&
- (fwrq->m <= (int) 248700000)) {
+ if (fwrq->e == 1) {
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 +2380,11 @@ 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 */
+
+ /* Values in MHz -> * 10^5 * 10 */
+ range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) *
+ 100000);
+ range->freq[k++].e = 1;
}
range->num_frequency = k;
}
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
index b33e13f..bef7360 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,13 +3719,13 @@ 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;
int err = 0;
u16 channel;
- long freq = 0;
+ int freq = 0;
unsigned long flags;

if (orinoco_lock(priv, &flags) != 0)
@@ -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,7 +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].m = (ieee80211_dsss_chan_to_freq(i + 1) *
+ 100000);
range->freq[k].e = 1;
k++;
}
@@ -4328,16 +4324,15 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
/* Setting by channel number */
chan = frq->m;
} else {
- /* Setting by frequency - search the table */
- int mult = 1;
+ /* Setting by frequency */
+ 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) ||
@@ -4374,7 +4369,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
return tmp;
}

- frq->m = tmp;
+ frq->m = tmp * 100000;
frq->e = 1;

return 0;
@@ -5595,7 +5590,7 @@ 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.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_FREQ_LEN);
@@ -5746,7 +5741,7 @@ 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.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
iwe.u.freq.e = 1;
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..78a3ba8 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,11 +1175,11 @@ 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].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
range->freq[i].e = 1;
}
range->num_frequency = i;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 68789c6..5e41756 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,7 +1507,7 @@ 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.m = ieee80211_dsss_chan_to_freq(this->chan) * 100000;
wrqu->freq.e = 1;
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..cade255 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1185,4 +1185,120 @@ 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 center frequency
+ * @channel: the DSSS channel
+ *
+ * Convert IEEE802.11 DSSS channel to the center 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 frequency
+ *
+ * Convert frequency (MHz) to IEEE802.11 DSSS channel
+ * Ref IEEE 802.11-2007 section 15.6
+ *
+ * This routine selects the channel with the closest center frequency.
+ */
+static inline int ieee80211_freq_to_dsss_chan(int freq)
+{
+ if ((freq >= 2410) && (freq < 2475))
+ return (freq - 2405) / 5;
+ else if ((freq >= 2482) && (freq < 2487))
+ 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 center frequency
+ * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
+ * @channel: the OFDM channel
+ *
+ * Convert IEEE802.11 OFDM channel to center 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 frequency
+ *
+ * Convert frequency (MHz) to IEEE802.11 OFDM channel
+ * Ref IEEE 802.11-2007 section 17.3.8.3.2
+ *
+ * This routine selects the channel with the closest center frequency.
+ */
+static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
+{
+ if ((freq > (s_freq + 2)) && (freq <= (s_freq + 1202)) &&
+ (s_freq >= 4000))
+ return (freq + 2 - s_freq) / 5;
+ else
+ return -1;
+}
+
#endif /* LINUX_IEEE80211_H */
--
1.5.6.4



2008-12-24 22:04:32

by Jussi Kivilinna

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

Quoting "David Kilroy" <[email protected]>:

> 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 the new functions in the older fullmac drivers. This eliminates a
> number of const static buffers and removes a couple of range checks that
> are now redundant.
>
> Signed-off-by: David Kilroy <[email protected]>

rndis_wlan part looks ok to me.

Acked-by: Jussi Kivilinna <[email protected]>


2008-12-23 20:22:26

by Dave Kilroy

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

Richard Farina wrote:
> David Kilroy wrote:
>> 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.

>> +/**
>> + * ieee80211_ofdm_chan_to_freq - get channel center frequency
>> + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
>> + * @channel: the OFDM channel
>> + *
>> + * Convert IEEE802.11 OFDM channel to center 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;
>> +}

> Any desire to make 184-196 work? These are the 4.9 GHz channels.

Do you see a reason why these channels wouldn't work with these
conversion routines? Or are you asking about corresponding driver support?

>From the ack I assume the latter. My main motivation is to put the
frequency conversions in a common place. In this case for old drivers
which only use the 2.4 GHz band. The 5GHz conversions are just for
completeness.

If drivers don't currently support those channels, I suspect there's a
more significant issue to be addressed first.

> I checked this all out pretty specifically, seems to work well. As if
> anyone cares but:
>
> ACKED-By: Rick Farina

Thanks for having a look.



Dave.

2008-12-23 16:10:06

by Sid Hayn

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

David Kilroy wrote:
> 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 the new functions in the older fullmac drivers. This eliminates a
> number of const static buffers and removes a couple of range checks that
> are now redundant.
>
> Signed-off-by: David Kilroy <[email protected]>
> ---
>
> This has changed from the RFC as follows:
>
> - freq_to_chan conversions return the channel with the closest
> center frequency (instead of rounding down)
> - Remove a couple frequency checks which are now redundant
> - Leaving the WE exponents alone
>
> Also note this changes the frequency reported by wl3501 for channel 14.
> I've assumed this is a fix...
>
> ---
> drivers/net/wireless/airo.c | 25 ++-----
> drivers/net/wireless/atmel.c | 20 ++---
> drivers/net/wireless/orinoco/orinoco.c | 33 ++++-----
> drivers/net/wireless/rndis_wlan.c | 13 ++--
> drivers/net/wireless/wl3501_cs.c | 9 +--
> drivers/net/wireless/zd1201.c | 7 +-
> include/linux/ieee80211.h | 116 ++++++++++++++++++++++++++++++++
> 7 files changed, 155 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
> index 45f8384..35f28ee 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
> @@ -5735,16 +5731,12 @@ static int airo_set_freq(struct net_device *dev,
> int rc = -EINPROGRESS; /* Call commit handler */
>
> /* If setting by frequency, convert to a channel */
> - if((fwrq->e == 1) &&
> - (fwrq->m >= (int) 2.412e8) &&
> - (fwrq->m <= (int) 2.487e8)) {
> + if(fwrq->e == 1) {
> 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,7 +5780,7 @@ 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->m = ieee80211_dsss_chan_to_freq(ch) * 100000;
> fwrq->e = 1;
> } else {
> fwrq->m = ch;
> @@ -6805,8 +6797,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) * 100000;
> + range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
> }
> range->num_frequency = k;
>
> @@ -7199,10 +7191,7 @@ 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.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000;
> iwe.u.freq.e = 1;
> 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..28dedb8 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,
> @@ -2219,16 +2216,12 @@ static int atmel_set_freq(struct net_device *dev,
> int rc = -EINPROGRESS; /* Call commit handler */
>
> /* If setting by frequency, convert to a channel */
> - if ((fwrq->e == 1) &&
> - (fwrq->m >= (int) 241200000) &&
> - (fwrq->m <= (int) 248700000)) {
> + if (fwrq->e == 1) {
> 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 +2380,11 @@ 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 */
> +
> + /* Values in MHz -> * 10^5 * 10 */
> + range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) *
> + 100000);
> + range->freq[k++].e = 1;
> }
> range->num_frequency = k;
> }
> diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
> index b33e13f..bef7360 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,13 +3719,13 @@ 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;
> int err = 0;
> u16 channel;
> - long freq = 0;
> + int freq = 0;
> unsigned long flags;
>
> if (orinoco_lock(priv, &flags) != 0)
> @@ -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,7 +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].m = (ieee80211_dsss_chan_to_freq(i + 1) *
> + 100000);
> range->freq[k].e = 1;
> k++;
> }
> @@ -4328,16 +4324,15 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
> /* Setting by channel number */
> chan = frq->m;
> } else {
> - /* Setting by frequency - search the table */
> - int mult = 1;
> + /* Setting by frequency */
> + 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) ||
> @@ -4374,7 +4369,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
> return tmp;
> }
>
> - frq->m = tmp;
> + frq->m = tmp * 100000;
> frq->e = 1;
>
> return 0;
> @@ -5595,7 +5590,7 @@ 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.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
> iwe.u.freq.e = 1;
> current_ev = iwe_stream_add_event(info, current_ev, end_buf,
> &iwe, IW_EV_FREQ_LEN);
> @@ -5746,7 +5741,7 @@ 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.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
> iwe.u.freq.e = 1;
> 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..78a3ba8 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,11 +1175,11 @@ 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].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
> range->freq[i].e = 1;
> }
> range->num_frequency = i;
> diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
> index 68789c6..5e41756 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,7 +1507,7 @@ 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.m = ieee80211_dsss_chan_to_freq(this->chan) * 100000;
> wrqu->freq.e = 1;
> 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..cade255 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -1185,4 +1185,120 @@ 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 center frequency
> + * @channel: the DSSS channel
> + *
> + * Convert IEEE802.11 DSSS channel to the center 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 frequency
> + *
> + * Convert frequency (MHz) to IEEE802.11 DSSS channel
> + * Ref IEEE 802.11-2007 section 15.6
> + *
> + * This routine selects the channel with the closest center frequency.
> + */
> +static inline int ieee80211_freq_to_dsss_chan(int freq)
> +{
> + if ((freq >= 2410) && (freq < 2475))
> + return (freq - 2405) / 5;
> + else if ((freq >= 2482) && (freq < 2487))
> + 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 center frequency
> + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
> + * @channel: the OFDM channel
> + *
> + * Convert IEEE802.11 OFDM channel to center 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;
> +}
>
Any desire to make 184-196 work? These are the 4.9 GHz channels.
> +
> +/**
> + * ieee80211_freq_to_ofdm_channel - get channel
> + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
> + * @freq: the frequency
> + *
> + * Convert frequency (MHz) to IEEE802.11 OFDM channel
> + * Ref IEEE 802.11-2007 section 17.3.8.3.2
> + *
> + * This routine selects the channel with the closest center frequency.
> + */
> +static inline int ieee80211_freq_to_ofdm_chan(int s_freq, int freq)
> +{
> + if ((freq > (s_freq + 2)) && (freq <= (s_freq + 1202)) &&
> + (s_freq >= 4000))
> + return (freq + 2 - s_freq) / 5;
> + else
> + return -1;
> +}
> +
>
Same as above.
> #endif /* LINUX_IEEE80211_H */
>

I checked this all out pretty specifically, seems to work well. As if
anyone cares but:

ACKED-By: Rick Farina

2008-12-23 20:51:56

by Jeroen Vreeken

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

David Kilroy wrote:
> 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 the new functions in the older fullmac drivers. This eliminates a
> number of const static buffers and removes a couple of range checks that
> are now redundant.
>
> Signed-off-by: David Kilroy <[email protected]>
>
Hi David,

The zd1201 stuff seems fine to me.

Acked-by: Jeroen Vreeken <[email protected]>


Regards,
Jeroen

2008-12-23 22:47:25

by Dave Kilroy

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

Richard Farina wrote:
> Dave wrote:
>> Richard Farina wrote:
>>> David Kilroy wrote:
>>>> 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.

>>>> +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;
>>>> +}

>>> Any desire to make 184-196 work? These are the 4.9 GHz channels.

>> Do you see a reason why these channels wouldn't work with these
>> conversion routines? Or are you asking about corresponding driver support?

> Channel 165 freq is 5825MHz
> Channel 183 freq is 4915MHz
>
> Since your method is linear and 183 is greater than 165, it will output
> a higher frequency for 183 than for 165 when converting from channel to
> freq.

I suspect you're talking about US regulatory class 5 which names channel
165 with a starting frequency of 5GHz, and Japans regulatory class 16-20
naming channel 183 with starting frequency 4GHz. These are accounted
for in the conversion routines by the s_freq parameter:

ieee80211_ofdm_chan_to_freq(5000, 165) ==> 5825
ieee80211_ofdm_chan_to_freq(4000, 183) ==> 4915

It means the caller must know the starting frequency when converting
OFDM channels and frequencies. I expect that this number will come from
the regulatory work that is underway (though I haven't been keeping
track of that).


Regards,

Dave.

>> If drivers don't currently support those channels, I suspect there's a
>> more significant issue to be addressed first.

> No drivers support these channels at the moment AFAIK but I'd be happy
> to submit a patch that enables tuning if someone else could submit a
> patch to support half/quarter clocked channels. Japan is the only place
> in the world that supports the 4.9GHz realm unlicensed, and I've already
> been told that patches that enabled licensed only features will not be
> accepted so I have not bothered to submit support as I lack the skill to
> add support for half/quarter clock channels and hence it wouldn't be
> unlicensed.
>
> Thanks,
> Rick Farina


2008-12-23 14:12:07

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

Em Tue, Dec 23, 2008 at 02:03:38PM +0000, David Kilroy escreveu:
> 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 the new functions in the older fullmac drivers. This eliminates a
> number of const static buffers and removes a couple of range checks that
> are now redundant.
>
> Signed-off-by: David Kilroy <[email protected]>

Acked-by: Arnaldo Carvalho de Melo <[email protected]>

2008-12-23 22:18:59

by Sid Hayn

[permalink] [raw]
Subject: Re: [PATCH] wireless: Add channel/frequency conversions to ieee80211.h

Dave wrote:
> Richard Farina wrote:
>
>> David Kilroy wrote:
>>
>>> 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.
>>>
>
>
>>> +/**
>>> + * ieee80211_ofdm_chan_to_freq - get channel center frequency
>>> + * @s_freq: starting frequency == (dotChannelStartingFactor/2) MHz
>>> + * @channel: the OFDM channel
>>> + *
>>> + * Convert IEEE802.11 OFDM channel to center 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;
>>> +}
>>>
>
>
>> Any desire to make 184-196 work? These are the 4.9 GHz channels.
>>
>
> Do you see a reason why these channels wouldn't work with these
> conversion routines? Or are you asking about corresponding driver support?
>
>
Channel 165 freq is 5825MHz
Channel 183 freq is 4915MHz

Since your method is linear and 183 is greater than 165, it will output
a higher frequency for 183 than for 165 when converting from channel to
freq.

Please feel free to correct me if I'm wrong, my coding skills are not
very good (hence the reason I have included a patch). Considering none
of the cards using this support 802.11a is doesn't seem to matter much,
but the fact of the matter is I have had to correct this stuff in a
driver or two and it would be nice if the drivers could pull this info
from a single place instead of each driver doing the conversions
(possibly wrongly) by themselves.
> >From the ack I assume the latter. My main motivation is to put the
> frequency conversions in a common place. In this case for old drivers
> which only use the 2.4 GHz band. The 5GHz conversions are just for
> completeness.
>
>
My request of supporting the 4.9 stuff is also only for completeness,
there is nothing at all that should stop you from committing your code
as is, no code I have seen accounts for proper conversion so your work
is by no means sub-par.
> If drivers don't currently support those channels, I suspect there's a
> more significant issue to be addressed first.
>
>
No drivers support these channels at the moment AFAIK but I'd be happy
to submit a patch that enables tuning if someone else could submit a
patch to support half/quarter clocked channels. Japan is the only place
in the world that supports the 4.9GHz realm unlicensed, and I've already
been told that patches that enabled licensed only features will not be
accepted so I have not bothered to submit support as I lack the skill to
add support for half/quarter clock channels and hence it wouldn't be
unlicensed.

Thanks,
Rick Farina
>> I checked this all out pretty specifically, seems to work well. As if
>> anyone cares but:
>>
>> ACKED-By: Rick Farina
>>
>
> Thanks for having a look.
>
>
>
> Dave.
>
>