blob: d2ca949174fe925c1b5a75a698e0ef27a8537bd5 [file] [log] [blame]
John W. Linvillef2223132006-01-23 16:59:58 -05001/*
2
3 Broadcom BCM43xx wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27 Boston, MA 02110-1301, USA.
28
29*/
30
31#include <linux/wireless.h>
32#include <net/iw_handler.h>
33#include <net/ieee80211softmac.h>
34#include <net/ieee80211softmac_wx.h>
35#include <linux/capability.h>
John W. Linvillef2223132006-01-23 16:59:58 -050036#include <linux/delay.h>
37
38#include "bcm43xx.h"
39#include "bcm43xx_wx.h"
40#include "bcm43xx_main.h"
41#include "bcm43xx_radio.h"
Michael Bueschb5488be2006-02-08 18:00:30 +010042#include "bcm43xx_phy.h"
John W. Linvillef2223132006-01-23 16:59:58 -050043
Michael Buesch8fa252d2006-02-02 19:49:15 +010044
45/* The WIRELESS_EXT version, which is implemented by this driver. */
46#define BCM43xx_WX_VERSION 18
47
John W. Linvillef2223132006-01-23 16:59:58 -050048#define MAX_WX_STRING 80
John W. Linvillef2223132006-01-23 16:59:58 -050049
50static int bcm43xx_wx_get_name(struct net_device *net_dev,
51 struct iw_request_info *info,
52 union iwreq_data *data,
53 char *extra)
54{
55 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Buesche9357c02006-03-13 19:27:34 +010056 int i;
John W. Linvillef2223132006-01-23 16:59:58 -050057 struct bcm43xx_phyinfo *phy;
58 char suffix[7] = { 0 };
59 int have_a = 0, have_b = 0, have_g = 0;
60
Michael Bueschefa6a372006-06-27 21:38:40 +020061 mutex_lock(&bcm->mutex);
Michael Buesche9357c02006-03-13 19:27:34 +010062 for (i = 0; i < bcm->nr_80211_available; i++) {
63 phy = &(bcm->core_80211_ext[i].phy);
John W. Linvillef2223132006-01-23 16:59:58 -050064 switch (phy->type) {
65 case BCM43xx_PHYTYPE_A:
66 have_a = 1;
67 break;
68 case BCM43xx_PHYTYPE_G:
69 have_g = 1;
70 case BCM43xx_PHYTYPE_B:
71 have_b = 1;
72 break;
73 default:
74 assert(0);
75 }
76 }
Michael Bueschefa6a372006-06-27 21:38:40 +020077 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -050078
79 i = 0;
80 if (have_a) {
81 suffix[i++] = 'a';
82 suffix[i++] = '/';
83 }
84 if (have_b) {
85 suffix[i++] = 'b';
86 suffix[i++] = '/';
87 }
88 if (have_g) {
89 suffix[i++] = 'g';
90 suffix[i++] = '/';
91 }
92 if (i != 0)
93 suffix[i - 1] = '\0';
94
95 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
96
97 return 0;
98}
99
100static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
101 struct iw_request_info *info,
102 union iwreq_data *data,
103 char *extra)
104{
105 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500106 unsigned long flags;
107 u8 channel;
108 int freq;
Michael Buesch10d8dd82006-02-19 22:08:48 +0100109 int err = -EINVAL;
John W. Linvillef2223132006-01-23 16:59:58 -0500110
Michael Bueschefa6a372006-06-27 21:38:40 +0200111 mutex_lock(&bcm->mutex);
112 spin_lock_irqsave(&bcm->irq_lock, flags);
113
John W. Linvillef2223132006-01-23 16:59:58 -0500114 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
115 channel = data->freq.m;
116 freq = bcm43xx_channel_to_freq(bcm, channel);
117 } else {
118 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
119 freq = data->freq.m;
120 }
Larry Fingerfc8fd342006-06-25 21:32:21 -0500121 if (!ieee80211_is_valid_channel(bcm->ieee, channel))
Michael Buesch10d8dd82006-02-19 22:08:48 +0100122 goto out_unlock;
Michael Buesch78ff56a2006-06-05 20:24:10 +0200123 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
John W. Linvillef2223132006-01-23 16:59:58 -0500124 //ieee80211softmac_disassoc(softmac, $REASON);
125 bcm43xx_mac_suspend(bcm);
126 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
127 bcm43xx_mac_enable(bcm);
Michael Buesch10d8dd82006-02-19 22:08:48 +0100128 } else {
Michael Buesche9357c02006-03-13 19:27:34 +0100129 bcm43xx_current_radio(bcm)->initial_channel = channel;
Michael Buesch10d8dd82006-02-19 22:08:48 +0100130 err = 0;
131 }
132out_unlock:
Michael Bueschefa6a372006-06-27 21:38:40 +0200133 spin_unlock_irqrestore(&bcm->irq_lock, flags);
134 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500135
136 return err;
137}
138
139static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
140 struct iw_request_info *info,
141 union iwreq_data *data,
142 char *extra)
143{
144 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Buesche9357c02006-03-13 19:27:34 +0100145 struct bcm43xx_radioinfo *radio;
John W. Linvillef2223132006-01-23 16:59:58 -0500146 int err = -ENODEV;
147 u16 channel;
148
Michael Bueschefa6a372006-06-27 21:38:40 +0200149 mutex_lock(&bcm->mutex);
Michael Buesche9357c02006-03-13 19:27:34 +0100150 radio = bcm43xx_current_radio(bcm);
151 channel = radio->channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500152 if (channel == 0xFF) {
Michael Buesche9357c02006-03-13 19:27:34 +0100153 channel = radio->initial_channel;
John W. Linvillef2223132006-01-23 16:59:58 -0500154 if (channel == 0xFF)
155 goto out_unlock;
156 }
157 assert(channel > 0 && channel <= 1000);
158 data->freq.e = 1;
159 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
160 data->freq.flags = 1;
161
162 err = 0;
163out_unlock:
Michael Bueschefa6a372006-06-27 21:38:40 +0200164 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500165
166 return err;
167}
168
169static int bcm43xx_wx_set_mode(struct net_device *net_dev,
170 struct iw_request_info *info,
171 union iwreq_data *data,
172 char *extra)
173{
174 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
175 unsigned long flags;
176 int mode;
177
John W. Linvillef2223132006-01-23 16:59:58 -0500178 mode = data->mode;
179 if (mode == IW_MODE_AUTO)
180 mode = BCM43xx_INITIAL_IWMODE;
181
Michael Bueschefa6a372006-06-27 21:38:40 +0200182 mutex_lock(&bcm->mutex);
183 spin_lock_irqsave(&bcm->irq_lock, flags);
Michael Buesch78ff56a2006-06-05 20:24:10 +0200184 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
Michael Buesch5b4b9772006-05-01 22:43:00 +0200185 if (bcm->ieee->iw_mode != mode)
186 bcm43xx_set_iwmode(bcm, mode);
187 } else
188 bcm->ieee->iw_mode = mode;
Michael Bueschefa6a372006-06-27 21:38:40 +0200189 spin_unlock_irqrestore(&bcm->irq_lock, flags);
190 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500191
192 return 0;
193}
194
195static int bcm43xx_wx_get_mode(struct net_device *net_dev,
196 struct iw_request_info *info,
197 union iwreq_data *data,
198 char *extra)
199{
200 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500201
Michael Bueschefa6a372006-06-27 21:38:40 +0200202 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500203 data->mode = bcm->ieee->iw_mode;
Michael Bueschefa6a372006-06-27 21:38:40 +0200204 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500205
206 return 0;
207}
208
John W. Linvillef2223132006-01-23 16:59:58 -0500209static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
210 struct iw_request_info *info,
211 union iwreq_data *data,
212 char *extra)
213{
214 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
215 struct iw_range *range = (struct iw_range *)extra;
216 const struct ieee80211_geo *geo;
John W. Linvillef2223132006-01-23 16:59:58 -0500217 int i, j;
Michael Buesche9357c02006-03-13 19:27:34 +0100218 struct bcm43xx_phyinfo *phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500219
John W. Linvillef2223132006-01-23 16:59:58 -0500220 data->data.length = sizeof(*range);
221 memset(range, 0, sizeof(*range));
222
223 //TODO: What about 802.11b?
224 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
225 range->throughput = 27 * 1000 * 1000;
226
227 range->max_qual.qual = 100;
Larry Fingerc576af42006-08-23 23:02:40 -0500228 range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
229 range->max_qual.noise = 146;
Larry Finger4221f982006-06-29 22:48:59 -0500230 range->max_qual.updated = IW_QUAL_ALL_UPDATED;
John W. Linvillef2223132006-01-23 16:59:58 -0500231
Larry Finger4221f982006-06-29 22:48:59 -0500232 range->avg_qual.qual = 50;
233 range->avg_qual.level = 0;
234 range->avg_qual.noise = 0;
235 range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
John W. Linvillef2223132006-01-23 16:59:58 -0500236
237 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
238 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
239 range->min_frag = MIN_FRAG_THRESHOLD;
240 range->max_frag = MAX_FRAG_THRESHOLD;
241
242 range->encoding_size[0] = 5;
243 range->encoding_size[1] = 13;
244 range->num_encoding_sizes = 2;
245 range->max_encoding_tokens = WEP_KEYS;
246
247 range->we_version_compiled = WIRELESS_EXT;
Michael Buesch8fa252d2006-02-02 19:49:15 +0100248 range->we_version_source = BCM43xx_WX_VERSION;
249
250 range->enc_capa = IW_ENC_CAPA_WPA |
251 IW_ENC_CAPA_WPA2 |
252 IW_ENC_CAPA_CIPHER_TKIP |
253 IW_ENC_CAPA_CIPHER_CCMP;
John W. Linvillef2223132006-01-23 16:59:58 -0500254
Michael Bueschefa6a372006-06-27 21:38:40 +0200255 mutex_lock(&bcm->mutex);
Michael Buesche9357c02006-03-13 19:27:34 +0100256 phy = bcm43xx_current_phy(bcm);
John W. Linvillef2223132006-01-23 16:59:58 -0500257
258 range->num_bitrates = 0;
259 i = 0;
Michael Buesche9357c02006-03-13 19:27:34 +0100260 if (phy->type == BCM43xx_PHYTYPE_A ||
261 phy->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -0500262 range->num_bitrates = 8;
263 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
264 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
265 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
266 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
267 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
268 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
269 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
270 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
271 }
Michael Buesche9357c02006-03-13 19:27:34 +0100272 if (phy->type == BCM43xx_PHYTYPE_B ||
273 phy->type == BCM43xx_PHYTYPE_G) {
John W. Linvillef2223132006-01-23 16:59:58 -0500274 range->num_bitrates += 4;
275 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
276 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
277 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
278 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
279 }
280
281 geo = ieee80211_get_geo(bcm->ieee);
282 range->num_channels = geo->a_channels + geo->bg_channels;
283 j = 0;
284 for (i = 0; i < geo->a_channels; i++) {
285 if (j == IW_MAX_FREQUENCIES)
286 break;
287 range->freq[j].i = j + 1;
288 range->freq[j].m = geo->a[i].freq;//FIXME?
289 range->freq[j].e = 1;
290 j++;
291 }
292 for (i = 0; i < geo->bg_channels; i++) {
293 if (j == IW_MAX_FREQUENCIES)
294 break;
295 range->freq[j].i = j + 1;
296 range->freq[j].m = geo->bg[i].freq;//FIXME?
297 range->freq[j].e = 1;
298 j++;
299 }
300 range->num_frequency = j;
301
Michael Bueschefa6a372006-06-27 21:38:40 +0200302 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500303
304 return 0;
305}
306
307static int bcm43xx_wx_set_nick(struct net_device *net_dev,
308 struct iw_request_info *info,
309 union iwreq_data *data,
310 char *extra)
311{
312 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500313 size_t len;
314
Michael Bueschefa6a372006-06-27 21:38:40 +0200315 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500316 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
317 memcpy(bcm->nick, extra, len);
318 bcm->nick[len] = '\0';
Michael Bueschefa6a372006-06-27 21:38:40 +0200319 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500320
321 return 0;
322}
323
324static int bcm43xx_wx_get_nick(struct net_device *net_dev,
325 struct iw_request_info *info,
326 union iwreq_data *data,
327 char *extra)
328{
329 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500330 size_t len;
331
Michael Bueschefa6a372006-06-27 21:38:40 +0200332 mutex_lock(&bcm->mutex);
Larry Fingerb978d022006-08-31 10:01:39 -0500333 len = strlen(bcm->nick);
John W. Linvillef2223132006-01-23 16:59:58 -0500334 memcpy(extra, bcm->nick, len);
335 data->data.length = (__u16)len;
336 data->data.flags = 1;
Michael Bueschefa6a372006-06-27 21:38:40 +0200337 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500338
339 return 0;
340}
341
342static int bcm43xx_wx_set_rts(struct net_device *net_dev,
343 struct iw_request_info *info,
344 union iwreq_data *data,
345 char *extra)
346{
347 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
348 unsigned long flags;
349 int err = -EINVAL;
350
Michael Bueschefa6a372006-06-27 21:38:40 +0200351 mutex_lock(&bcm->mutex);
352 spin_lock_irqsave(&bcm->irq_lock, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500353 if (data->rts.disabled) {
354 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
355 err = 0;
356 } else {
357 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
358 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
359 bcm->rts_threshold = data->rts.value;
360 err = 0;
361 }
362 }
Michael Bueschefa6a372006-06-27 21:38:40 +0200363 spin_unlock_irqrestore(&bcm->irq_lock, flags);
364 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500365
366 return err;
367}
368
369static int bcm43xx_wx_get_rts(struct net_device *net_dev,
370 struct iw_request_info *info,
371 union iwreq_data *data,
372 char *extra)
373{
374 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500375
Michael Bueschefa6a372006-06-27 21:38:40 +0200376 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500377 data->rts.value = bcm->rts_threshold;
378 data->rts.fixed = 0;
379 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
Michael Bueschefa6a372006-06-27 21:38:40 +0200380 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500381
382 return 0;
383}
384
385static int bcm43xx_wx_set_frag(struct net_device *net_dev,
386 struct iw_request_info *info,
387 union iwreq_data *data,
388 char *extra)
389{
390 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
391 unsigned long flags;
392 int err = -EINVAL;
393
Michael Bueschefa6a372006-06-27 21:38:40 +0200394 mutex_lock(&bcm->mutex);
395 spin_lock_irqsave(&bcm->irq_lock, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500396 if (data->frag.disabled) {
397 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
398 err = 0;
399 } else {
400 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
401 data->frag.value <= MAX_FRAG_THRESHOLD) {
402 bcm->ieee->fts = data->frag.value & ~0x1;
403 err = 0;
404 }
405 }
Michael Bueschefa6a372006-06-27 21:38:40 +0200406 spin_unlock_irqrestore(&bcm->irq_lock, flags);
407 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500408
409 return err;
410}
411
412static int bcm43xx_wx_get_frag(struct net_device *net_dev,
413 struct iw_request_info *info,
414 union iwreq_data *data,
415 char *extra)
416{
417 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500418
Michael Bueschefa6a372006-06-27 21:38:40 +0200419 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500420 data->frag.value = bcm->ieee->fts;
421 data->frag.fixed = 0;
422 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
Michael Bueschefa6a372006-06-27 21:38:40 +0200423 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500424
425 return 0;
426}
427
428static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
429 struct iw_request_info *info,
430 union iwreq_data *data,
431 char *extra)
432{
433 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Buesch393344f2006-02-05 15:28:20 +0100434 struct bcm43xx_radioinfo *radio;
435 struct bcm43xx_phyinfo *phy;
John W. Linvillef2223132006-01-23 16:59:58 -0500436 unsigned long flags;
437 int err = -ENODEV;
Michael Buesch393344f2006-02-05 15:28:20 +0100438 u16 maxpower;
John W. Linvillef2223132006-01-23 16:59:58 -0500439
Michael Buesch393344f2006-02-05 15:28:20 +0100440 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
441 printk(PFX KERN_ERR "TX power not in dBm.\n");
442 return -EOPNOTSUPP;
443 }
444
Michael Bueschefa6a372006-06-27 21:38:40 +0200445 mutex_lock(&bcm->mutex);
446 spin_lock_irqsave(&bcm->irq_lock, flags);
Michael Buesch78ff56a2006-06-05 20:24:10 +0200447 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
John W. Linvillef2223132006-01-23 16:59:58 -0500448 goto out_unlock;
Michael Buesche9357c02006-03-13 19:27:34 +0100449 radio = bcm43xx_current_radio(bcm);
450 phy = bcm43xx_current_phy(bcm);
Michael Buesch393344f2006-02-05 15:28:20 +0100451 if (data->txpower.disabled != (!(radio->enabled))) {
452 if (data->txpower.disabled)
John W. Linvillef2223132006-01-23 16:59:58 -0500453 bcm43xx_radio_turn_off(bcm);
454 else
455 bcm43xx_radio_turn_on(bcm);
456 }
Michael Buesch393344f2006-02-05 15:28:20 +0100457 if (data->txpower.value > 0) {
458 /* desired and maxpower dBm values are in Q5.2 */
459 if (phy->type == BCM43xx_PHYTYPE_A)
460 maxpower = bcm->sprom.maxpower_aphy;
461 else
462 maxpower = bcm->sprom.maxpower_bgphy;
463 radio->txpower_desired = limit_value(data->txpower.value << 2,
464 0, maxpower);
465 bcm43xx_phy_xmitpower(bcm);
466 }
John W. Linvillef2223132006-01-23 16:59:58 -0500467 err = 0;
468
469out_unlock:
Michael Bueschefa6a372006-06-27 21:38:40 +0200470 spin_unlock_irqrestore(&bcm->irq_lock, flags);
471 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500472
473 return err;
474}
475
476static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
477 struct iw_request_info *info,
478 union iwreq_data *data,
479 char *extra)
480{
481 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Buesch393344f2006-02-05 15:28:20 +0100482 struct bcm43xx_radioinfo *radio;
Michael Buesch393344f2006-02-05 15:28:20 +0100483 int err = -ENODEV;
John W. Linvillef2223132006-01-23 16:59:58 -0500484
Michael Bueschefa6a372006-06-27 21:38:40 +0200485 mutex_lock(&bcm->mutex);
Michael Buesch78ff56a2006-06-05 20:24:10 +0200486 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
Michael Buesch393344f2006-02-05 15:28:20 +0100487 goto out_unlock;
Michael Buesche9357c02006-03-13 19:27:34 +0100488 radio = bcm43xx_current_radio(bcm);
Michael Buesch393344f2006-02-05 15:28:20 +0100489 /* desired dBm value is in Q5.2 */
490 data->txpower.value = radio->txpower_desired >> 2;
491 data->txpower.fixed = 1;
492 data->txpower.flags = IW_TXPOW_DBM;
493 data->txpower.disabled = !(radio->enabled);
494
495 err = 0;
496out_unlock:
Michael Bueschefa6a372006-06-27 21:38:40 +0200497 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500498
Michael Buesch393344f2006-02-05 15:28:20 +0100499 return err;
John W. Linvillef2223132006-01-23 16:59:58 -0500500}
501
John W. Linvillef2223132006-01-23 16:59:58 -0500502static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
503 struct iw_request_info *info,
504 union iwreq_data *data,
505 char *extra)
506{
507 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
508 int err;
509
John W. Linvillef2223132006-01-23 16:59:58 -0500510 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
511
512 return err;
513}
514
515static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
516 struct iw_request_info *info,
517 union iwreq_data *data,
518 char *extra)
519{
520 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
521 int err;
522
John W. Linvillef2223132006-01-23 16:59:58 -0500523 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
524
525 return err;
526}
527
528static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
529 struct iw_request_info *info,
530 union iwreq_data *data,
531 char *extra)
532{
533 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
534 int err;
535
John W. Linvillef2223132006-01-23 16:59:58 -0500536 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
537
538 return err;
539}
540
541static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
542 struct iw_request_info *info,
543 union iwreq_data *data,
544 char *extra)
545{
546 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
547 int err;
548
John W. Linvillef2223132006-01-23 16:59:58 -0500549 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
550
551 return err;
552}
553
John W. Linvillef2223132006-01-23 16:59:58 -0500554static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
555 struct iw_request_info *info,
556 union iwreq_data *data,
557 char *extra)
558{
559 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
560 unsigned long flags;
561 int mode, err = 0;
562
John W. Linvillef2223132006-01-23 16:59:58 -0500563 mode = *((int *)extra);
564 switch (mode) {
565 case 0:
566 mode = BCM43xx_RADIO_INTERFMODE_NONE;
567 break;
568 case 1:
569 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
570 break;
571 case 2:
572 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
573 break;
574 case 3:
575 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
576 break;
577 default:
578 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
579 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
580 "3 => Auto-WLAN\n");
581 return -EINVAL;
582 }
583
Michael Bueschefa6a372006-06-27 21:38:40 +0200584 mutex_lock(&bcm->mutex);
585 spin_lock_irqsave(&bcm->irq_lock, flags);
Michael Buesch78ff56a2006-06-05 20:24:10 +0200586 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
John W. Linvillef2223132006-01-23 16:59:58 -0500587 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
588 if (err) {
589 printk(KERN_ERR PFX "Interference Mitigation not "
590 "supported by device\n");
591 }
592 } else {
593 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
594 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
595 "not supported while the interface is down.\n");
596 err = -ENODEV;
597 } else
Michael Buesche9357c02006-03-13 19:27:34 +0100598 bcm43xx_current_radio(bcm)->interfmode = mode;
John W. Linvillef2223132006-01-23 16:59:58 -0500599 }
Michael Bueschefa6a372006-06-27 21:38:40 +0200600 spin_unlock_irqrestore(&bcm->irq_lock, flags);
601 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500602
603 return err;
604}
605
606static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
607 struct iw_request_info *info,
608 union iwreq_data *data,
609 char *extra)
610{
611 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500612 int mode;
613
Michael Bueschefa6a372006-06-27 21:38:40 +0200614 mutex_lock(&bcm->mutex);
Michael Buesche9357c02006-03-13 19:27:34 +0100615 mode = bcm43xx_current_radio(bcm)->interfmode;
Michael Bueschefa6a372006-06-27 21:38:40 +0200616 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500617
618 switch (mode) {
619 case BCM43xx_RADIO_INTERFMODE_NONE:
620 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
621 break;
622 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
623 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
624 break;
625 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
626 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
627 break;
628 default:
629 assert(0);
630 }
631 data->data.length = strlen(extra) + 1;
632
633 return 0;
634}
635
636static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
637 struct iw_request_info *info,
638 union iwreq_data *data,
639 char *extra)
640{
641 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
642 unsigned long flags;
643 int on;
644
John W. Linvillef2223132006-01-23 16:59:58 -0500645 on = *((int *)extra);
Michael Bueschefa6a372006-06-27 21:38:40 +0200646 mutex_lock(&bcm->mutex);
647 spin_lock_irqsave(&bcm->irq_lock, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500648 bcm->short_preamble = !!on;
Michael Bueschefa6a372006-06-27 21:38:40 +0200649 spin_unlock_irqrestore(&bcm->irq_lock, flags);
650 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500651
652 return 0;
653}
654
655static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
656 struct iw_request_info *info,
657 union iwreq_data *data,
658 char *extra)
659{
660 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500661 int on;
662
Michael Bueschefa6a372006-06-27 21:38:40 +0200663 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500664 on = bcm->short_preamble;
Michael Bueschefa6a372006-06-27 21:38:40 +0200665 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500666
667 if (on)
668 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
669 else
670 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
671 data->data.length = strlen(extra) + 1;
672
673 return 0;
674}
675
676static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
677 struct iw_request_info *info,
678 union iwreq_data *data,
679 char *extra)
680{
681 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
682 unsigned long flags;
683 int on;
684
John W. Linvillef2223132006-01-23 16:59:58 -0500685 on = *((int *)extra);
Michael Bueschefccb642006-03-11 13:39:14 +0100686
Michael Bueschefa6a372006-06-27 21:38:40 +0200687 mutex_lock(&bcm->mutex);
688 spin_lock_irqsave(&bcm->irq_lock, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500689 bcm->ieee->host_encrypt = !!on;
690 bcm->ieee->host_decrypt = !!on;
691 bcm->ieee->host_build_iv = !on;
Daniel Drakec9308b02006-09-27 03:50:31 +0100692 bcm->ieee->host_strip_iv_icv = !on;
Michael Bueschefa6a372006-06-27 21:38:40 +0200693 spin_unlock_irqrestore(&bcm->irq_lock, flags);
694 mutex_unlock(&bcm->mutex);
Michael Bueschefccb642006-03-11 13:39:14 +0100695
John W. Linvillef2223132006-01-23 16:59:58 -0500696 return 0;
697}
698
699static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
700 struct iw_request_info *info,
701 union iwreq_data *data,
702 char *extra)
703{
704 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
John W. Linvillef2223132006-01-23 16:59:58 -0500705 int on;
Michael Bueschefccb642006-03-11 13:39:14 +0100706
Michael Bueschefa6a372006-06-27 21:38:40 +0200707 mutex_lock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500708 on = bcm->ieee->host_encrypt;
Michael Bueschefa6a372006-06-27 21:38:40 +0200709 mutex_unlock(&bcm->mutex);
Michael Bueschefccb642006-03-11 13:39:14 +0100710
John W. Linvillef2223132006-01-23 16:59:58 -0500711 if (on)
712 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
713 else
714 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
715 data->data.length = strlen(extra + 1);
Michael Bueschefccb642006-03-11 13:39:14 +0100716
John W. Linvillef2223132006-01-23 16:59:58 -0500717 return 0;
718}
719
720/* Enough buffer to hold a hexdump of the sprom data. */
721#define SPROM_BUFFERSIZE 512
722
723static int sprom2hex(const u16 *sprom, char *dump)
724{
725 int i, pos = 0;
726
727 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
728 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
729 "%04X", swab16(sprom[i]) & 0xFFFF);
730 }
731
732 return pos + 1;
733}
734
735static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
736{
737 char tmp[5] = { 0 };
738 int cnt = 0;
739 unsigned long parsed;
John W. Linvillef2223132006-01-23 16:59:58 -0500740
741 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
742 return -EINVAL;
743 while (cnt < BCM43xx_SPROM_SIZE) {
744 memcpy(tmp, dump, 4);
745 dump += 4;
746 parsed = simple_strtoul(tmp, NULL, 16);
747 sprom[cnt++] = swab16((u16)parsed);
748 }
749
John W. Linvillef2223132006-01-23 16:59:58 -0500750 return 0;
751}
752
753static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
754 struct iw_request_info *info,
755 union iwreq_data *data,
756 char *extra)
757{
758 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
Michael Bueschea0922b2006-02-19 14:09:20 +0100759 int err = -EPERM;
John W. Linvillef2223132006-01-23 16:59:58 -0500760 u16 *sprom;
761 unsigned long flags;
762
763 if (!capable(CAP_SYS_RAWIO))
764 goto out;
765
766 err = -ENOMEM;
767 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
768 GFP_KERNEL);
769 if (!sprom)
770 goto out;
771
Michael Bueschefa6a372006-06-27 21:38:40 +0200772 mutex_lock(&bcm->mutex);
773 spin_lock_irqsave(&bcm->irq_lock, flags);
John W. Linvillef2223132006-01-23 16:59:58 -0500774 err = -ENODEV;
Michael Buesch78ff56a2006-06-05 20:24:10 +0200775 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
Michael Bueschefccb642006-03-11 13:39:14 +0100776 err = bcm43xx_sprom_read(bcm, sprom);
Michael Bueschefa6a372006-06-27 21:38:40 +0200777 spin_unlock_irqrestore(&bcm->irq_lock, flags);
778 mutex_unlock(&bcm->mutex);
Michael Bueschea0922b2006-02-19 14:09:20 +0100779 if (!err)
780 data->data.length = sprom2hex(sprom, extra);
John W. Linvillef2223132006-01-23 16:59:58 -0500781 kfree(sprom);
782out:
783 return err;
784}
785
786static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
787 struct iw_request_info *info,
788 union iwreq_data *data,
789 char *extra)
790{
791 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
792 int err = -EPERM;
793 u16 *sprom;
794 unsigned long flags;
795 char *input;
796 unsigned int len;
John W. Linvillef2223132006-01-23 16:59:58 -0500797
798 if (!capable(CAP_SYS_RAWIO))
799 goto out;
800
801 err = -ENOMEM;
802 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
803 GFP_KERNEL);
804 if (!sprom)
805 goto out;
806
807 len = data->data.length;
808 extra[len - 1] = '\0';
809 input = strchr(extra, ':');
810 if (input) {
811 input++;
812 len -= input - extra;
813 } else
814 input = extra;
815 err = hex2sprom(sprom, input, len);
816 if (err)
817 goto out_kfree;
818
Michael Bueschefa6a372006-06-27 21:38:40 +0200819 mutex_lock(&bcm->mutex);
820 spin_lock_irqsave(&bcm->irq_lock, flags);
821 spin_lock(&bcm->leds_lock);
John W. Linvillef2223132006-01-23 16:59:58 -0500822 err = -ENODEV;
Michael Buesch78ff56a2006-06-05 20:24:10 +0200823 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
Michael Bueschefccb642006-03-11 13:39:14 +0100824 err = bcm43xx_sprom_write(bcm, sprom);
Michael Bueschefa6a372006-06-27 21:38:40 +0200825 spin_unlock(&bcm->leds_lock);
826 spin_unlock_irqrestore(&bcm->irq_lock, flags);
827 mutex_unlock(&bcm->mutex);
John W. Linvillef2223132006-01-23 16:59:58 -0500828out_kfree:
829 kfree(sprom);
830out:
831 return err;
832}
833
Michael Buesch72fb8512006-03-22 18:10:19 +0100834/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
835
836static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
837{
838 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
839 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
840 struct iw_statistics *wstats;
Larry Finger4221f982006-06-29 22:48:59 -0500841 struct ieee80211_network *network = NULL;
842 static int tmp_level = 0;
Larry Finger27be44f2006-07-14 15:42:17 -0500843 static int tmp_qual = 0;
Larry Finger4221f982006-06-29 22:48:59 -0500844 unsigned long flags;
Michael Buesch72fb8512006-03-22 18:10:19 +0100845
846 wstats = &bcm->stats.wstats;
Michael Buesch7c28ad22006-09-27 15:26:33 +0300847 if (!mac->associnfo.associated) {
Michael Buesch72fb8512006-03-22 18:10:19 +0100848 wstats->miss.beacon = 0;
849// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
850 wstats->discard.retries = 0;
851// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
852 wstats->discard.nwid = 0;
853// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
854 wstats->discard.code = 0;
855// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
856 wstats->discard.fragment = 0;
857 wstats->discard.misc = 0;
858 wstats->qual.qual = 0;
859 wstats->qual.level = 0;
860 wstats->qual.noise = 0;
861 wstats->qual.updated = 7;
Larry Finger27be44f2006-07-14 15:42:17 -0500862 wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Michael Buesch72fb8512006-03-22 18:10:19 +0100863 return wstats;
864 }
865 /* fill in the real statistics when iface associated */
Larry Finger4221f982006-06-29 22:48:59 -0500866 spin_lock_irqsave(&mac->ieee->lock, flags);
867 list_for_each_entry(network, &mac->ieee->network_list, list) {
868 if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
Larry Finger27be44f2006-07-14 15:42:17 -0500869 if (!tmp_level) { /* get initial values */
870 tmp_level = network->stats.signal;
871 tmp_qual = network->stats.rssi;
872 } else { /* smooth results */
873 tmp_level = (15 * tmp_level + network->stats.signal)/16;
874 tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
875 }
Larry Finger4221f982006-06-29 22:48:59 -0500876 break;
877 }
878 }
879 spin_unlock_irqrestore(&mac->ieee->lock, flags);
880 wstats->qual.level = tmp_level;
Larry Finger27be44f2006-07-14 15:42:17 -0500881 wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
Michael Buesch72fb8512006-03-22 18:10:19 +0100882 wstats->qual.noise = bcm->stats.noise;
Larry Finger27be44f2006-07-14 15:42:17 -0500883 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
Michael Buesch72fb8512006-03-22 18:10:19 +0100884 wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
885 wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
886 wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
887 wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
888 wstats->discard.misc = 0; // FIXME
889 wstats->miss.beacon = 0; // FIXME
890 return wstats;
891}
892
John W. Linvillef2223132006-01-23 16:59:58 -0500893
894#ifdef WX
895# undef WX
896#endif
897#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
898static const iw_handler bcm43xx_wx_handlers[] = {
899 /* Wireless Identification */
900 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
901 /* Basic operations */
902 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
903 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
904 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
905 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
906 /* Informative stuff */
907 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
908 /* Access Point manipulation */
909 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
910 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
911 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
912 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
913 /* 802.11 specific support */
914 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
915 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
916 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
917 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
918 /* Other parameters */
919 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
920 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
921 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
922 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
923 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
924 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
925 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
926 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
927//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
928//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
929 /* Encoding */
930 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
931 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
932 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
933 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
934 /* Power saving */
935//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
936//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
937 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
938 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
939 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
940 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
941};
942#undef WX
943
944static const iw_handler bcm43xx_priv_wx_handlers[] = {
945 /* Set Interference Mitigation Mode. */
946 bcm43xx_wx_set_interfmode,
947 /* Get Interference Mitigation Mode. */
948 bcm43xx_wx_get_interfmode,
949 /* Enable/Disable Short Preamble mode. */
950 bcm43xx_wx_set_shortpreamble,
951 /* Get Short Preamble mode. */
952 bcm43xx_wx_get_shortpreamble,
953 /* Enable/Disable Software Encryption mode */
954 bcm43xx_wx_set_swencryption,
955 /* Get Software Encryption mode */
956 bcm43xx_wx_get_swencryption,
957 /* Write SRPROM data. */
958 bcm43xx_wx_sprom_write,
959 /* Read SPROM data. */
960 bcm43xx_wx_sprom_read,
961};
962
963#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
964#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
965#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
966#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
967#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
968#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
969#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
970#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
971
972#define PRIV_WX_DUMMY(ioctl) \
973 { \
974 .cmd = (ioctl), \
975 .name = "__unused" \
976 }
977
978static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
979 {
980 .cmd = PRIV_WX_SET_INTERFMODE,
981 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
982 .name = "set_interfmode",
983 },
984 {
985 .cmd = PRIV_WX_GET_INTERFMODE,
986 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
987 .name = "get_interfmode",
988 },
989 {
990 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
991 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
Erik Mouwa3921492006-04-13 15:02:27 +0200992 .name = "set_shortpreamb",
John W. Linvillef2223132006-01-23 16:59:58 -0500993 },
994 {
995 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
996 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
Erik Mouwa3921492006-04-13 15:02:27 +0200997 .name = "get_shortpreamb",
John W. Linvillef2223132006-01-23 16:59:58 -0500998 },
999 {
1000 .cmd = PRIV_WX_SET_SWENCRYPTION,
1001 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
Erik Mouwa3921492006-04-13 15:02:27 +02001002 .name = "set_swencrypt",
John W. Linvillef2223132006-01-23 16:59:58 -05001003 },
1004 {
1005 .cmd = PRIV_WX_GET_SWENCRYPTION,
1006 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
Erik Mouwa3921492006-04-13 15:02:27 +02001007 .name = "get_swencrypt",
John W. Linvillef2223132006-01-23 16:59:58 -05001008 },
1009 {
1010 .cmd = PRIV_WX_SPROM_WRITE,
1011 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
1012 .name = "write_sprom",
1013 },
1014 {
1015 .cmd = PRIV_WX_SPROM_READ,
1016 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1017 .name = "read_sprom",
1018 },
1019};
1020
1021const struct iw_handler_def bcm43xx_wx_handlers_def = {
1022 .standard = bcm43xx_wx_handlers,
1023 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
1024 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1025 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
1026 .private = bcm43xx_priv_wx_handlers,
1027 .private_args = bcm43xx_priv_wx_args,
Michael Buesch72fb8512006-03-22 18:10:19 +01001028 .get_wireless_stats = bcm43xx_get_wireless_stats,
John W. Linvillef2223132006-01-23 16:59:58 -05001029};