diff options
author | Daniel Drake <dsd@gentoo.org> | 2007-11-19 15:00:29 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 15:04:47 -0800 |
commit | 459c51ad6e1fc19e91a53798358433d3c08cd09d (patch) | |
tree | fb86feacf1b229cb4ab6b36b4d1deaf4983b1e45 /drivers/net/wireless/zd1211rw/zd_ieee80211.c | |
parent | 0765af4493193149505f118d04d9300f0a15c8f5 (diff) |
zd1211rw: port to mac80211
This seems to be working smoothly now. Let's not hold back the mac80211
transition any further. This patch ports the existing driver from softmac
to mac80211.
Many thanks to everyone who helped out with the porting efforts.
Signed-off-by: Daniel Drake <dsd@gentoo.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_ieee80211.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_ieee80211.c | 191 |
1 files changed, 49 insertions, 142 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c index 189160efd2ae..77cfe5e78230 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c @@ -16,178 +16,85 @@ */ /* - * A lot of this code is generic and should be moved into the upper layers - * at some point. + * In the long term, we'll probably find a better way of handling regulatory + * requirements outside of the driver. */ -#include <linux/errno.h> -#include <linux/wireless.h> #include <linux/kernel.h> -#include <net/ieee80211.h> +#include <net/mac80211.h> -#include "zd_def.h" #include "zd_ieee80211.h" #include "zd_mac.h" +struct channel_range { + u8 regdomain; + u8 start; + u8 end; /* exclusive (channel must be less than end) */ +}; + static const struct channel_range channel_ranges[] = { - [0] = { 0, 0}, - [ZD_REGDOMAIN_FCC] = { 1, 12}, - [ZD_REGDOMAIN_IC] = { 1, 12}, - [ZD_REGDOMAIN_ETSI] = { 1, 14}, - [ZD_REGDOMAIN_JAPAN] = { 1, 14}, - [ZD_REGDOMAIN_SPAIN] = { 1, 14}, - [ZD_REGDOMAIN_FRANCE] = { 1, 14}, + { ZD_REGDOMAIN_FCC, 1, 12 }, + { ZD_REGDOMAIN_IC, 1, 12 }, + { ZD_REGDOMAIN_ETSI, 1, 14 }, + { ZD_REGDOMAIN_JAPAN, 1, 14 }, + { ZD_REGDOMAIN_SPAIN, 1, 14 }, + { ZD_REGDOMAIN_FRANCE, 1, 14 }, /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in * 802.11). However, in 2001 the range was extended to include channels * 1-13. The ZyDAS devices still use the old region code but are * designed to allow the extra channel access in Japan. */ - [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15}, + { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 }, }; -const struct channel_range *zd_channel_range(u8 regdomain) -{ - if (regdomain >= ARRAY_SIZE(channel_ranges)) - regdomain = 0; - return &channel_ranges[regdomain]; -} - -int zd_regdomain_supports_channel(u8 regdomain, u8 channel) -{ - const struct channel_range *range = zd_channel_range(regdomain); - return range->start <= channel && channel < range->end; -} - -int zd_regdomain_supported(u8 regdomain) +static const struct channel_range *zd_channel_range(u8 regdomain) { - const struct channel_range *range = zd_channel_range(regdomain); - return range->start != 0; -} - -/* Stores channel frequencies in MHz. */ -static const u16 channel_frequencies[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, 2472, 2484, -}; - -#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies) - -static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz) -{ - u32 factor; - - freq->e = 0; - if (mhz >= 1000000000U) { - pr_debug("zd1211 mhz %u to large\n", mhz); - freq->m = 0; - return -EINVAL; - } - - factor = 1000; - while (mhz >= factor) { - - freq->e += 1; - factor *= 10; - } - - factor /= 1000U; - freq->m = mhz * (1000000U/factor) + hz/factor; - - return 0; -} - -int zd_channel_to_freq(struct iw_freq *freq, u8 channel) -{ - if (channel > NUM_CHANNELS) { - freq->m = 0; - freq->e = 0; - return -EINVAL; - } - if (!channel) { - freq->m = 0; - freq->e = 0; - return -EINVAL; + int i; + for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) { + const struct channel_range *range = &channel_ranges[i]; + if (range->regdomain == regdomain) + return range; } - return compute_freq(freq, channel_frequencies[channel-1], 0); + return NULL; } -static int freq_to_mhz(const struct iw_freq *freq) -{ - u32 factor; - int e; - - /* Such high frequencies are not supported. */ - if (freq->e > 6) - return -EINVAL; - - factor = 1; - for (e = freq->e; e > 0; --e) { - factor *= 10; - } - factor = 1000000U / factor; - - if (freq->m % factor) { - return -EINVAL; - } - - return freq->m / factor; -} +#define CHAN_TO_IDX(chan) ((chan) - 1) -int zd_find_channel(u8 *channel, const struct iw_freq *freq) +static void unmask_bg_channels(struct ieee80211_hw *hw, + const struct channel_range *range, + struct ieee80211_hw_mode *mode) { - int i, r; - u32 mhz; - - if (freq->m < 1000) { - if (freq->m > NUM_CHANNELS || freq->m == 0) - return -EINVAL; - *channel = freq->m; - return 1; - } - - r = freq_to_mhz(freq); - if (r < 0) - return r; - mhz = r; + u8 channel; - for (i = 0; i < NUM_CHANNELS; i++) { - if (mhz == channel_frequencies[i]) { - *channel = i+1; - return 1; - } + for (channel = range->start; channel < range->end; channel++) { + struct ieee80211_channel *chan = + &mode->channels[CHAN_TO_IDX(channel)]; + chan->flag |= IEEE80211_CHAN_W_SCAN | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_IBSS; } - - return -EINVAL; } -int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain) +void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) { - struct ieee80211_geo geo; + struct zd_mac *mac = zd_hw_mac(hw); const struct channel_range *range; - int i; - u8 channel; - dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "regdomain %#04x\n", regdomain); + dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain); range = zd_channel_range(regdomain); - if (range->start == 0) { - dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "zd1211 regdomain %#04x not supported\n", - regdomain); - return -EINVAL; + if (!range) { + /* The vendor driver overrides the regulatory domain and + * allowed channel registers and unconditionally restricts + * available channels to 1-11 everywhere. Match their + * questionable behaviour only for regdomains which we don't + * recognise. */ + dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " + "%#02x. Defaulting to FCC.\n", regdomain); + range = zd_channel_range(ZD_REGDOMAIN_FCC); } - memset(&geo, 0, sizeof(geo)); - - for (i = 0, channel = range->start; channel < range->end; channel++) { - struct ieee80211_channel *chan = &geo.bg[i++]; - chan->freq = channel_frequencies[channel - 1]; - chan->channel = channel; - } - - geo.bg_channels = i; - memcpy(geo.name, "XX ", 4); - ieee80211_set_geo(ieee, &geo); - return 0; + unmask_bg_channels(hw, range, &mac->modes[0]); + unmask_bg_channels(hw, range, &mac->modes[1]); } + |