]>
Commit | Line | Data |
---|---|---|
ea60a6aa DK |
1 | /* cfg80211 support |
2 | * | |
3 | * See copyright notice in main.c | |
4 | */ | |
5 | #include <linux/ieee80211.h> | |
6 | #include <net/cfg80211.h> | |
7 | #include "hw.h" | |
8 | #include "main.h" | |
9 | #include "orinoco.h" | |
10 | ||
11 | #include "cfg.h" | |
12 | ||
13 | /* Supported bitrates. Must agree with hw.c */ | |
14 | static struct ieee80211_rate orinoco_rates[] = { | |
15 | { .bitrate = 10 }, | |
16 | { .bitrate = 20 }, | |
17 | { .bitrate = 55 }, | |
18 | { .bitrate = 110 }, | |
19 | }; | |
20 | ||
21 | static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid; | |
22 | ||
23 | /* Called after orinoco_private is allocated. */ | |
24 | void orinoco_wiphy_init(struct wiphy *wiphy) | |
25 | { | |
26 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
27 | ||
28 | wiphy->privid = orinoco_wiphy_privid; | |
29 | ||
30 | set_wiphy_dev(wiphy, priv->dev); | |
31 | } | |
32 | ||
33 | /* Called after firmware is initialised */ | |
34 | int orinoco_wiphy_register(struct wiphy *wiphy) | |
35 | { | |
36 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
37 | int i, channels = 0; | |
38 | ||
39 | if (priv->firmware_type == FIRMWARE_TYPE_AGERE) | |
40 | wiphy->max_scan_ssids = 1; | |
41 | else | |
42 | wiphy->max_scan_ssids = 0; | |
43 | ||
44 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
45 | ||
46 | /* TODO: should we set if we only have demo ad-hoc? | |
47 | * (priv->has_port3) | |
48 | */ | |
49 | if (priv->has_ibss) | |
50 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); | |
51 | ||
52 | if (!priv->broken_monitor || force_monitor) | |
53 | wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | |
54 | ||
55 | priv->band.bitrates = orinoco_rates; | |
56 | priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates); | |
57 | ||
58 | /* Only support channels allowed by the card EEPROM */ | |
59 | for (i = 0; i < NUM_CHANNELS; i++) { | |
60 | if (priv->channel_mask & (1 << i)) { | |
61 | priv->channels[i].center_freq = | |
62 | ieee80211_dsss_chan_to_freq(i+1); | |
63 | channels++; | |
64 | } | |
65 | } | |
66 | priv->band.channels = priv->channels; | |
67 | priv->band.n_channels = channels; | |
68 | ||
69 | wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; | |
70 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | |
71 | ||
72 | i = 0; | |
73 | if (priv->has_wep) { | |
74 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40; | |
75 | i++; | |
76 | ||
77 | if (priv->has_big_wep) { | |
78 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104; | |
79 | i++; | |
80 | } | |
81 | } | |
82 | if (priv->has_wpa) { | |
83 | priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP; | |
84 | i++; | |
85 | } | |
86 | wiphy->cipher_suites = priv->cipher_suites; | |
87 | wiphy->n_cipher_suites = i; | |
88 | ||
89 | wiphy->rts_threshold = priv->rts_thresh; | |
90 | if (!priv->has_mwo) | |
c3d41503 DK |
91 | wiphy->frag_threshold = priv->frag_thresh + 1; |
92 | wiphy->retry_short = priv->short_retry_limit; | |
93 | wiphy->retry_long = priv->long_retry_limit; | |
ea60a6aa DK |
94 | |
95 | return wiphy_register(wiphy); | |
96 | } | |
97 | ||
5217c571 DK |
98 | static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, |
99 | enum nl80211_iftype type, u32 *flags, | |
100 | struct vif_params *params) | |
101 | { | |
102 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
103 | int err = 0; | |
104 | unsigned long lock; | |
105 | ||
106 | if (orinoco_lock(priv, &lock) != 0) | |
107 | return -EBUSY; | |
108 | ||
109 | switch (type) { | |
110 | case NL80211_IFTYPE_ADHOC: | |
111 | if (!priv->has_ibss && !priv->has_port3) | |
112 | err = -EINVAL; | |
113 | break; | |
114 | ||
115 | case NL80211_IFTYPE_STATION: | |
116 | break; | |
117 | ||
118 | case NL80211_IFTYPE_MONITOR: | |
119 | if (priv->broken_monitor && !force_monitor) { | |
120 | printk(KERN_WARNING "%s: Monitor mode support is " | |
121 | "buggy in this firmware, not enabling\n", | |
122 | wiphy_name(wiphy)); | |
123 | err = -EINVAL; | |
124 | } | |
125 | break; | |
126 | ||
127 | default: | |
128 | err = -EINVAL; | |
129 | } | |
ea60a6aa | 130 | |
5217c571 DK |
131 | if (!err) { |
132 | priv->iw_mode = type; | |
133 | set_port_type(priv); | |
134 | err = orinoco_commit(priv); | |
135 | } | |
136 | ||
137 | orinoco_unlock(priv, &lock); | |
138 | ||
139 | return err; | |
140 | } | |
141 | ||
c63cdbe8 DK |
142 | static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, |
143 | struct cfg80211_scan_request *request) | |
144 | { | |
145 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
146 | int err; | |
147 | ||
148 | if (!request) | |
149 | return -EINVAL; | |
150 | ||
151 | if (priv->scan_request && priv->scan_request != request) | |
152 | return -EBUSY; | |
153 | ||
154 | priv->scan_request = request; | |
155 | ||
156 | err = orinoco_hw_trigger_scan(priv, request->ssids); | |
157 | ||
158 | return err; | |
159 | } | |
160 | ||
7e2ce646 | 161 | static int orinoco_set_channel(struct wiphy *wiphy, |
f444de05 | 162 | struct net_device *netdev, |
7e2ce646 HS |
163 | struct ieee80211_channel *chan, |
164 | enum nl80211_channel_type channel_type) | |
165 | { | |
166 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
167 | int err = 0; | |
168 | unsigned long flags; | |
169 | int channel; | |
170 | ||
171 | if (!chan) | |
172 | return -EINVAL; | |
173 | ||
174 | if (channel_type != NL80211_CHAN_NO_HT) | |
175 | return -EINVAL; | |
176 | ||
177 | if (chan->band != IEEE80211_BAND_2GHZ) | |
178 | return -EINVAL; | |
179 | ||
180 | channel = ieee80211_freq_to_dsss_chan(chan->center_freq); | |
181 | ||
182 | if ((channel < 1) || (channel > NUM_CHANNELS) || | |
183 | !(priv->channel_mask & (1 << (channel-1)))) | |
184 | return -EINVAL; | |
185 | ||
186 | if (orinoco_lock(priv, &flags) != 0) | |
187 | return -EBUSY; | |
188 | ||
189 | priv->channel = channel; | |
190 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { | |
191 | /* Fast channel change - no commit if successful */ | |
192 | hermes_t *hw = &priv->hw; | |
b42f2074 | 193 | err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | |
7e2ce646 HS |
194 | HERMES_TEST_SET_CHANNEL, |
195 | channel, NULL); | |
196 | } | |
197 | orinoco_unlock(priv, &flags); | |
198 | ||
199 | return err; | |
200 | } | |
201 | ||
c3d41503 DK |
202 | static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
203 | { | |
204 | struct orinoco_private *priv = wiphy_priv(wiphy); | |
205 | int frag_value = -1; | |
206 | int rts_value = -1; | |
207 | int err = 0; | |
208 | ||
209 | if (changed & WIPHY_PARAM_RETRY_SHORT) { | |
210 | /* Setting short retry not supported */ | |
211 | err = -EINVAL; | |
212 | } | |
213 | ||
214 | if (changed & WIPHY_PARAM_RETRY_LONG) { | |
215 | /* Setting long retry not supported */ | |
216 | err = -EINVAL; | |
217 | } | |
218 | ||
219 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | |
220 | /* Set fragmentation */ | |
221 | if (priv->has_mwo) { | |
222 | if (wiphy->frag_threshold < 0) | |
223 | frag_value = 0; | |
224 | else { | |
225 | printk(KERN_WARNING "%s: Fixed fragmentation " | |
226 | "is not supported on this firmware. " | |
227 | "Using MWO robust instead.\n", | |
228 | priv->ndev->name); | |
229 | frag_value = 1; | |
230 | } | |
231 | } else { | |
232 | if (wiphy->frag_threshold < 0) | |
233 | frag_value = 2346; | |
234 | else if ((wiphy->frag_threshold < 257) || | |
235 | (wiphy->frag_threshold > 2347)) | |
236 | err = -EINVAL; | |
237 | else | |
238 | /* cfg80211 value is 257-2347 (odd only) | |
239 | * orinoco rid has range 256-2346 (even only) */ | |
240 | frag_value = wiphy->frag_threshold & ~0x1; | |
241 | } | |
242 | } | |
243 | ||
244 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | |
245 | /* Set RTS. | |
246 | * | |
247 | * Prism documentation suggests default of 2432, | |
248 | * and a range of 0-3000. | |
249 | * | |
250 | * Current implementation uses 2347 as the default and | |
251 | * the upper limit. | |
252 | */ | |
253 | ||
254 | if (wiphy->rts_threshold < 0) | |
255 | rts_value = 2347; | |
256 | else if (wiphy->rts_threshold > 2347) | |
257 | err = -EINVAL; | |
258 | else | |
259 | rts_value = wiphy->rts_threshold; | |
260 | } | |
261 | ||
262 | if (!err) { | |
263 | unsigned long flags; | |
264 | ||
265 | if (orinoco_lock(priv, &flags) != 0) | |
266 | return -EBUSY; | |
267 | ||
268 | if (frag_value >= 0) { | |
269 | if (priv->has_mwo) | |
270 | priv->mwo_robust = frag_value; | |
271 | else | |
272 | priv->frag_thresh = frag_value; | |
273 | } | |
274 | if (rts_value >= 0) | |
275 | priv->rts_thresh = rts_value; | |
276 | ||
277 | err = orinoco_commit(priv); | |
278 | ||
279 | orinoco_unlock(priv, &flags); | |
280 | } | |
281 | ||
282 | return err; | |
283 | } | |
284 | ||
5217c571 DK |
285 | const struct cfg80211_ops orinoco_cfg_ops = { |
286 | .change_virtual_intf = orinoco_change_vif, | |
7e2ce646 | 287 | .set_channel = orinoco_set_channel, |
c63cdbe8 | 288 | .scan = orinoco_scan, |
c3d41503 | 289 | .set_wiphy_params = orinoco_set_wiphy_params, |
ea60a6aa | 290 | }; |