aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/zd1211rw/zd_ieee80211.c
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2007-11-19 10:00:29 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:04:47 -0500
commit459c51ad6e1fc19e91a53798358433d3c08cd09d (patch)
treefb86feacf1b229cb4ab6b36b4d1deaf4983b1e45 /drivers/net/wireless/zd1211rw/zd_ieee80211.c
parent0765af4493193149505f118d04d9300f0a15c8f5 (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.c191
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 @@
16 */ 16 */
17 17
18/* 18/*
19 * A lot of this code is generic and should be moved into the upper layers 19 * In the long term, we'll probably find a better way of handling regulatory
20 * at some point. 20 * requirements outside of the driver.
21 */ 21 */
22 22
23#include <linux/errno.h>
24#include <linux/wireless.h>
25#include <linux/kernel.h> 23#include <linux/kernel.h>
26#include <net/ieee80211.h> 24#include <net/mac80211.h>
27 25
28#include "zd_def.h"
29#include "zd_ieee80211.h" 26#include "zd_ieee80211.h"
30#include "zd_mac.h" 27#include "zd_mac.h"
31 28
29struct channel_range {
30 u8 regdomain;
31 u8 start;
32 u8 end; /* exclusive (channel must be less than end) */
33};
34
32static const struct channel_range channel_ranges[] = { 35static const struct channel_range channel_ranges[] = {
33 [0] = { 0, 0}, 36 { ZD_REGDOMAIN_FCC, 1, 12 },
34 [ZD_REGDOMAIN_FCC] = { 1, 12}, 37 { ZD_REGDOMAIN_IC, 1, 12 },
35 [ZD_REGDOMAIN_IC] = { 1, 12}, 38 { ZD_REGDOMAIN_ETSI, 1, 14 },
36 [ZD_REGDOMAIN_ETSI] = { 1, 14}, 39 { ZD_REGDOMAIN_JAPAN, 1, 14 },
37 [ZD_REGDOMAIN_JAPAN] = { 1, 14}, 40 { ZD_REGDOMAIN_SPAIN, 1, 14 },
38 [ZD_REGDOMAIN_SPAIN] = { 1, 14}, 41 { ZD_REGDOMAIN_FRANCE, 1, 14 },
39 [ZD_REGDOMAIN_FRANCE] = { 1, 14},
40 42
41 /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in 43 /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
42 * 802.11). However, in 2001 the range was extended to include channels 44 * 802.11). However, in 2001 the range was extended to include channels
43 * 1-13. The ZyDAS devices still use the old region code but are 45 * 1-13. The ZyDAS devices still use the old region code but are
44 * designed to allow the extra channel access in Japan. */ 46 * designed to allow the extra channel access in Japan. */
45 [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15}, 47 { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 },
46}; 48};
47 49
48const struct channel_range *zd_channel_range(u8 regdomain) 50static const struct channel_range *zd_channel_range(u8 regdomain)
49{
50 if (regdomain >= ARRAY_SIZE(channel_ranges))
51 regdomain = 0;
52 return &channel_ranges[regdomain];
53}
54
55int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
56{
57 const struct channel_range *range = zd_channel_range(regdomain);
58 return range->start <= channel && channel < range->end;
59}
60
61int zd_regdomain_supported(u8 regdomain)
62{ 51{
63 const struct channel_range *range = zd_channel_range(regdomain); 52 int i;
64 return range->start != 0; 53 for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) {
65} 54 const struct channel_range *range = &channel_ranges[i];
66 55 if (range->regdomain == regdomain)
67/* Stores channel frequencies in MHz. */ 56 return range;
68static const u16 channel_frequencies[] = {
69 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
70 2452, 2457, 2462, 2467, 2472, 2484,
71};
72
73#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
74
75static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
76{
77 u32 factor;
78
79 freq->e = 0;
80 if (mhz >= 1000000000U) {
81 pr_debug("zd1211 mhz %u to large\n", mhz);
82 freq->m = 0;
83 return -EINVAL;
84 }
85
86 factor = 1000;
87 while (mhz >= factor) {
88
89 freq->e += 1;
90 factor *= 10;
91 }
92
93 factor /= 1000U;
94 freq->m = mhz * (1000000U/factor) + hz/factor;
95
96 return 0;
97}
98
99int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
100{
101 if (channel > NUM_CHANNELS) {
102 freq->m = 0;
103 freq->e = 0;
104 return -EINVAL;
105 }
106 if (!channel) {
107 freq->m = 0;
108 freq->e = 0;
109 return -EINVAL;
110 } 57 }
111 return compute_freq(freq, channel_frequencies[channel-1], 0); 58 return NULL;
112} 59}
113 60
114static int freq_to_mhz(const struct iw_freq *freq) 61#define CHAN_TO_IDX(chan) ((chan) - 1)
115{
116 u32 factor;
117 int e;
118
119 /* Such high frequencies are not supported. */
120 if (freq->e > 6)
121 return -EINVAL;
122
123 factor = 1;
124 for (e = freq->e; e > 0; --e) {
125 factor *= 10;
126 }
127 factor = 1000000U / factor;
128
129 if (freq->m % factor) {
130 return -EINVAL;
131 }
132
133 return freq->m / factor;
134}
135 62
136int zd_find_channel(u8 *channel, const struct iw_freq *freq) 63static void unmask_bg_channels(struct ieee80211_hw *hw,
64 const struct channel_range *range,
65 struct ieee80211_hw_mode *mode)
137{ 66{
138 int i, r; 67 u8 channel;
139 u32 mhz;
140
141 if (freq->m < 1000) {
142 if (freq->m > NUM_CHANNELS || freq->m == 0)
143 return -EINVAL;
144 *channel = freq->m;
145 return 1;
146 }
147
148 r = freq_to_mhz(freq);
149 if (r < 0)
150 return r;
151 mhz = r;
152 68
153 for (i = 0; i < NUM_CHANNELS; i++) { 69 for (channel = range->start; channel < range->end; channel++) {
154 if (mhz == channel_frequencies[i]) { 70 struct ieee80211_channel *chan =
155 *channel = i+1; 71 &mode->channels[CHAN_TO_IDX(channel)];
156 return 1; 72 chan->flag |= IEEE80211_CHAN_W_SCAN |
157 } 73 IEEE80211_CHAN_W_ACTIVE_SCAN |
74 IEEE80211_CHAN_W_IBSS;
158 } 75 }
159
160 return -EINVAL;
161} 76}
162 77
163int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain) 78void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
164{ 79{
165 struct ieee80211_geo geo; 80 struct zd_mac *mac = zd_hw_mac(hw);
166 const struct channel_range *range; 81 const struct channel_range *range;
167 int i;
168 u8 channel;
169 82
170 dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)), 83 dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain);
171 "regdomain %#04x\n", regdomain);
172 84
173 range = zd_channel_range(regdomain); 85 range = zd_channel_range(regdomain);
174 if (range->start == 0) { 86 if (!range) {
175 dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)), 87 /* The vendor driver overrides the regulatory domain and
176 "zd1211 regdomain %#04x not supported\n", 88 * allowed channel registers and unconditionally restricts
177 regdomain); 89 * available channels to 1-11 everywhere. Match their
178 return -EINVAL; 90 * questionable behaviour only for regdomains which we don't
91 * recognise. */
92 dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
93 "%#02x. Defaulting to FCC.\n", regdomain);
94 range = zd_channel_range(ZD_REGDOMAIN_FCC);
179 } 95 }
180 96
181 memset(&geo, 0, sizeof(geo)); 97 unmask_bg_channels(hw, range, &mac->modes[0]);
182 98 unmask_bg_channels(hw, range, &mac->modes[1]);
183 for (i = 0, channel = range->start; channel < range->end; channel++) {
184 struct ieee80211_channel *chan = &geo.bg[i++];
185 chan->freq = channel_frequencies[channel - 1];
186 chan->channel = channel;
187 }
188
189 geo.bg_channels = i;
190 memcpy(geo.name, "XX ", 4);
191 ieee80211_set_geo(ieee, &geo);
192 return 0;
193} 99}
100