PCIE: check and return bus_register errors
[linux-2.6/next.git] / drivers / net / wireless / bcm43xx / bcm43xx_wx.c
blob888077fc14c457b7082e706d503754efc9b46ab3
1 /*
3 Broadcom BCM43xx wireless driver
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>
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
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.
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.
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.
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>
36 #include <linux/sched.h> /* for capable() */
37 #include <linux/delay.h>
39 #include "bcm43xx.h"
40 #include "bcm43xx_wx.h"
41 #include "bcm43xx_main.h"
42 #include "bcm43xx_radio.h"
43 #include "bcm43xx_phy.h"
46 /* The WIRELESS_EXT version, which is implemented by this driver. */
47 #define BCM43xx_WX_VERSION 18
49 #define MAX_WX_STRING 80
50 /* FIXME: the next line is a guess as to what the maximum RSSI value might be */
51 #define RX_RSSI_MAX 60
54 static int bcm43xx_wx_get_name(struct net_device *net_dev,
55 struct iw_request_info *info,
56 union iwreq_data *data,
57 char *extra)
59 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
60 int i;
61 struct bcm43xx_phyinfo *phy;
62 char suffix[7] = { 0 };
63 int have_a = 0, have_b = 0, have_g = 0;
65 mutex_lock(&bcm->mutex);
66 for (i = 0; i < bcm->nr_80211_available; i++) {
67 phy = &(bcm->core_80211_ext[i].phy);
68 switch (phy->type) {
69 case BCM43xx_PHYTYPE_A:
70 have_a = 1;
71 break;
72 case BCM43xx_PHYTYPE_G:
73 have_g = 1;
74 case BCM43xx_PHYTYPE_B:
75 have_b = 1;
76 break;
77 default:
78 assert(0);
81 mutex_unlock(&bcm->mutex);
83 i = 0;
84 if (have_a) {
85 suffix[i++] = 'a';
86 suffix[i++] = '/';
88 if (have_b) {
89 suffix[i++] = 'b';
90 suffix[i++] = '/';
92 if (have_g) {
93 suffix[i++] = 'g';
94 suffix[i++] = '/';
96 if (i != 0)
97 suffix[i - 1] = '\0';
99 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
101 return 0;
104 static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
105 struct iw_request_info *info,
106 union iwreq_data *data,
107 char *extra)
109 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
110 unsigned long flags;
111 u8 channel;
112 int freq;
113 int err = -EINVAL;
115 mutex_lock(&bcm->mutex);
116 spin_lock_irqsave(&bcm->irq_lock, flags);
118 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
119 channel = data->freq.m;
120 freq = bcm43xx_channel_to_freq(bcm, channel);
121 } else {
122 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
123 freq = data->freq.m;
125 if (!ieee80211_is_valid_channel(bcm->ieee, channel))
126 goto out_unlock;
127 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
128 //ieee80211softmac_disassoc(softmac, $REASON);
129 bcm43xx_mac_suspend(bcm);
130 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
131 bcm43xx_mac_enable(bcm);
132 } else {
133 bcm43xx_current_radio(bcm)->initial_channel = channel;
134 err = 0;
136 out_unlock:
137 spin_unlock_irqrestore(&bcm->irq_lock, flags);
138 mutex_unlock(&bcm->mutex);
140 return err;
143 static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
144 struct iw_request_info *info,
145 union iwreq_data *data,
146 char *extra)
148 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
149 struct bcm43xx_radioinfo *radio;
150 int err = -ENODEV;
151 u16 channel;
153 mutex_lock(&bcm->mutex);
154 radio = bcm43xx_current_radio(bcm);
155 channel = radio->channel;
156 if (channel == 0xFF) {
157 channel = radio->initial_channel;
158 if (channel == 0xFF)
159 goto out_unlock;
161 assert(channel > 0 && channel <= 1000);
162 data->freq.e = 1;
163 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
164 data->freq.flags = 1;
166 err = 0;
167 out_unlock:
168 mutex_unlock(&bcm->mutex);
170 return err;
173 static int bcm43xx_wx_set_mode(struct net_device *net_dev,
174 struct iw_request_info *info,
175 union iwreq_data *data,
176 char *extra)
178 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
179 unsigned long flags;
180 int mode;
182 mode = data->mode;
183 if (mode == IW_MODE_AUTO)
184 mode = BCM43xx_INITIAL_IWMODE;
186 mutex_lock(&bcm->mutex);
187 spin_lock_irqsave(&bcm->irq_lock, flags);
188 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
189 if (bcm->ieee->iw_mode != mode)
190 bcm43xx_set_iwmode(bcm, mode);
191 } else
192 bcm->ieee->iw_mode = mode;
193 spin_unlock_irqrestore(&bcm->irq_lock, flags);
194 mutex_unlock(&bcm->mutex);
196 return 0;
199 static int bcm43xx_wx_get_mode(struct net_device *net_dev,
200 struct iw_request_info *info,
201 union iwreq_data *data,
202 char *extra)
204 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
206 mutex_lock(&bcm->mutex);
207 data->mode = bcm->ieee->iw_mode;
208 mutex_unlock(&bcm->mutex);
210 return 0;
213 static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
214 struct iw_request_info *info,
215 union iwreq_data *data,
216 char *extra)
218 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
219 struct iw_range *range = (struct iw_range *)extra;
220 const struct ieee80211_geo *geo;
221 int i, j;
222 struct bcm43xx_phyinfo *phy;
224 data->data.length = sizeof(*range);
225 memset(range, 0, sizeof(*range));
227 //TODO: What about 802.11b?
228 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
229 range->throughput = 27 * 1000 * 1000;
231 range->max_qual.qual = 100;
232 range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
233 range->max_qual.noise = 146;
234 range->max_qual.updated = IW_QUAL_ALL_UPDATED;
236 range->avg_qual.qual = 50;
237 range->avg_qual.level = 0;
238 range->avg_qual.noise = 0;
239 range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
241 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
242 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
243 range->min_frag = MIN_FRAG_THRESHOLD;
244 range->max_frag = MAX_FRAG_THRESHOLD;
246 range->encoding_size[0] = 5;
247 range->encoding_size[1] = 13;
248 range->num_encoding_sizes = 2;
249 range->max_encoding_tokens = WEP_KEYS;
251 range->we_version_compiled = WIRELESS_EXT;
252 range->we_version_source = BCM43xx_WX_VERSION;
254 range->enc_capa = IW_ENC_CAPA_WPA |
255 IW_ENC_CAPA_WPA2 |
256 IW_ENC_CAPA_CIPHER_TKIP |
257 IW_ENC_CAPA_CIPHER_CCMP;
259 mutex_lock(&bcm->mutex);
260 phy = bcm43xx_current_phy(bcm);
262 range->num_bitrates = 0;
263 i = 0;
264 if (phy->type == BCM43xx_PHYTYPE_A ||
265 phy->type == BCM43xx_PHYTYPE_G) {
266 range->num_bitrates = 8;
267 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
268 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
269 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
270 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
271 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
272 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
273 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
274 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
276 if (phy->type == BCM43xx_PHYTYPE_B ||
277 phy->type == BCM43xx_PHYTYPE_G) {
278 range->num_bitrates += 4;
279 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
280 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
281 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
282 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
285 geo = ieee80211_get_geo(bcm->ieee);
286 range->num_channels = geo->a_channels + geo->bg_channels;
287 j = 0;
288 for (i = 0; i < geo->a_channels; i++) {
289 if (j == IW_MAX_FREQUENCIES)
290 break;
291 range->freq[j].i = j + 1;
292 range->freq[j].m = geo->a[i].freq;//FIXME?
293 range->freq[j].e = 1;
294 j++;
296 for (i = 0; i < geo->bg_channels; i++) {
297 if (j == IW_MAX_FREQUENCIES)
298 break;
299 range->freq[j].i = j + 1;
300 range->freq[j].m = geo->bg[i].freq;//FIXME?
301 range->freq[j].e = 1;
302 j++;
304 range->num_frequency = j;
306 mutex_unlock(&bcm->mutex);
308 return 0;
311 static int bcm43xx_wx_set_nick(struct net_device *net_dev,
312 struct iw_request_info *info,
313 union iwreq_data *data,
314 char *extra)
316 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
317 size_t len;
319 mutex_lock(&bcm->mutex);
320 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
321 memcpy(bcm->nick, extra, len);
322 bcm->nick[len] = '\0';
323 mutex_unlock(&bcm->mutex);
325 return 0;
328 static int bcm43xx_wx_get_nick(struct net_device *net_dev,
329 struct iw_request_info *info,
330 union iwreq_data *data,
331 char *extra)
333 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
334 size_t len;
336 mutex_lock(&bcm->mutex);
337 len = strlen(bcm->nick) + 1;
338 memcpy(extra, bcm->nick, len);
339 data->data.length = (__u16)len;
340 data->data.flags = 1;
341 mutex_unlock(&bcm->mutex);
343 return 0;
346 static int bcm43xx_wx_set_rts(struct net_device *net_dev,
347 struct iw_request_info *info,
348 union iwreq_data *data,
349 char *extra)
351 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
352 unsigned long flags;
353 int err = -EINVAL;
355 mutex_lock(&bcm->mutex);
356 spin_lock_irqsave(&bcm->irq_lock, flags);
357 if (data->rts.disabled) {
358 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
359 err = 0;
360 } else {
361 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
362 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
363 bcm->rts_threshold = data->rts.value;
364 err = 0;
367 spin_unlock_irqrestore(&bcm->irq_lock, flags);
368 mutex_unlock(&bcm->mutex);
370 return err;
373 static int bcm43xx_wx_get_rts(struct net_device *net_dev,
374 struct iw_request_info *info,
375 union iwreq_data *data,
376 char *extra)
378 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
380 mutex_lock(&bcm->mutex);
381 data->rts.value = bcm->rts_threshold;
382 data->rts.fixed = 0;
383 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
384 mutex_unlock(&bcm->mutex);
386 return 0;
389 static int bcm43xx_wx_set_frag(struct net_device *net_dev,
390 struct iw_request_info *info,
391 union iwreq_data *data,
392 char *extra)
394 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
395 unsigned long flags;
396 int err = -EINVAL;
398 mutex_lock(&bcm->mutex);
399 spin_lock_irqsave(&bcm->irq_lock, flags);
400 if (data->frag.disabled) {
401 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
402 err = 0;
403 } else {
404 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
405 data->frag.value <= MAX_FRAG_THRESHOLD) {
406 bcm->ieee->fts = data->frag.value & ~0x1;
407 err = 0;
410 spin_unlock_irqrestore(&bcm->irq_lock, flags);
411 mutex_unlock(&bcm->mutex);
413 return err;
416 static int bcm43xx_wx_get_frag(struct net_device *net_dev,
417 struct iw_request_info *info,
418 union iwreq_data *data,
419 char *extra)
421 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
423 mutex_lock(&bcm->mutex);
424 data->frag.value = bcm->ieee->fts;
425 data->frag.fixed = 0;
426 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
427 mutex_unlock(&bcm->mutex);
429 return 0;
432 static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
433 struct iw_request_info *info,
434 union iwreq_data *data,
435 char *extra)
437 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
438 struct bcm43xx_radioinfo *radio;
439 struct bcm43xx_phyinfo *phy;
440 unsigned long flags;
441 int err = -ENODEV;
442 u16 maxpower;
444 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
445 printk(PFX KERN_ERR "TX power not in dBm.\n");
446 return -EOPNOTSUPP;
449 mutex_lock(&bcm->mutex);
450 spin_lock_irqsave(&bcm->irq_lock, flags);
451 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
452 goto out_unlock;
453 radio = bcm43xx_current_radio(bcm);
454 phy = bcm43xx_current_phy(bcm);
455 if (data->txpower.disabled != (!(radio->enabled))) {
456 if (data->txpower.disabled)
457 bcm43xx_radio_turn_off(bcm);
458 else
459 bcm43xx_radio_turn_on(bcm);
461 if (data->txpower.value > 0) {
462 /* desired and maxpower dBm values are in Q5.2 */
463 if (phy->type == BCM43xx_PHYTYPE_A)
464 maxpower = bcm->sprom.maxpower_aphy;
465 else
466 maxpower = bcm->sprom.maxpower_bgphy;
467 radio->txpower_desired = limit_value(data->txpower.value << 2,
468 0, maxpower);
469 bcm43xx_phy_xmitpower(bcm);
471 err = 0;
473 out_unlock:
474 spin_unlock_irqrestore(&bcm->irq_lock, flags);
475 mutex_unlock(&bcm->mutex);
477 return err;
480 static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
481 struct iw_request_info *info,
482 union iwreq_data *data,
483 char *extra)
485 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
486 struct bcm43xx_radioinfo *radio;
487 int err = -ENODEV;
489 mutex_lock(&bcm->mutex);
490 if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
491 goto out_unlock;
492 radio = bcm43xx_current_radio(bcm);
493 /* desired dBm value is in Q5.2 */
494 data->txpower.value = radio->txpower_desired >> 2;
495 data->txpower.fixed = 1;
496 data->txpower.flags = IW_TXPOW_DBM;
497 data->txpower.disabled = !(radio->enabled);
499 err = 0;
500 out_unlock:
501 mutex_unlock(&bcm->mutex);
503 return err;
506 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
507 struct iw_request_info *info,
508 union iwreq_data *data,
509 char *extra)
511 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
512 int err;
514 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
516 return err;
519 static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
520 struct iw_request_info *info,
521 union iwreq_data *data,
522 char *extra)
524 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
525 int err;
527 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
529 return err;
532 static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
533 struct iw_request_info *info,
534 union iwreq_data *data,
535 char *extra)
537 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
538 int err;
540 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
542 return err;
545 static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
546 struct iw_request_info *info,
547 union iwreq_data *data,
548 char *extra)
550 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
551 int err;
553 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
555 return err;
558 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
559 struct iw_request_info *info,
560 union iwreq_data *data,
561 char *extra)
563 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
564 unsigned long flags;
565 int mode, err = 0;
567 mode = *((int *)extra);
568 switch (mode) {
569 case 0:
570 mode = BCM43xx_RADIO_INTERFMODE_NONE;
571 break;
572 case 1:
573 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
574 break;
575 case 2:
576 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
577 break;
578 case 3:
579 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
580 break;
581 default:
582 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
583 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
584 "3 => Auto-WLAN\n");
585 return -EINVAL;
588 mutex_lock(&bcm->mutex);
589 spin_lock_irqsave(&bcm->irq_lock, flags);
590 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
591 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
592 if (err) {
593 printk(KERN_ERR PFX "Interference Mitigation not "
594 "supported by device\n");
596 } else {
597 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
598 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
599 "not supported while the interface is down.\n");
600 err = -ENODEV;
601 } else
602 bcm43xx_current_radio(bcm)->interfmode = mode;
604 spin_unlock_irqrestore(&bcm->irq_lock, flags);
605 mutex_unlock(&bcm->mutex);
607 return err;
610 static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
611 struct iw_request_info *info,
612 union iwreq_data *data,
613 char *extra)
615 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
616 int mode;
618 mutex_lock(&bcm->mutex);
619 mode = bcm43xx_current_radio(bcm)->interfmode;
620 mutex_unlock(&bcm->mutex);
622 switch (mode) {
623 case BCM43xx_RADIO_INTERFMODE_NONE:
624 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
625 break;
626 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
627 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
628 break;
629 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
630 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
631 break;
632 default:
633 assert(0);
635 data->data.length = strlen(extra) + 1;
637 return 0;
640 static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
641 struct iw_request_info *info,
642 union iwreq_data *data,
643 char *extra)
645 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
646 unsigned long flags;
647 int on;
649 on = *((int *)extra);
650 mutex_lock(&bcm->mutex);
651 spin_lock_irqsave(&bcm->irq_lock, flags);
652 bcm->short_preamble = !!on;
653 spin_unlock_irqrestore(&bcm->irq_lock, flags);
654 mutex_unlock(&bcm->mutex);
656 return 0;
659 static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
660 struct iw_request_info *info,
661 union iwreq_data *data,
662 char *extra)
664 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
665 int on;
667 mutex_lock(&bcm->mutex);
668 on = bcm->short_preamble;
669 mutex_unlock(&bcm->mutex);
671 if (on)
672 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
673 else
674 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
675 data->data.length = strlen(extra) + 1;
677 return 0;
680 static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
681 struct iw_request_info *info,
682 union iwreq_data *data,
683 char *extra)
685 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
686 unsigned long flags;
687 int on;
689 on = *((int *)extra);
691 mutex_lock(&bcm->mutex);
692 spin_lock_irqsave(&bcm->irq_lock, flags);
693 bcm->ieee->host_encrypt = !!on;
694 bcm->ieee->host_decrypt = !!on;
695 bcm->ieee->host_build_iv = !on;
696 spin_unlock_irqrestore(&bcm->irq_lock, flags);
697 mutex_unlock(&bcm->mutex);
699 return 0;
702 static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
703 struct iw_request_info *info,
704 union iwreq_data *data,
705 char *extra)
707 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
708 int on;
710 mutex_lock(&bcm->mutex);
711 on = bcm->ieee->host_encrypt;
712 mutex_unlock(&bcm->mutex);
714 if (on)
715 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
716 else
717 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
718 data->data.length = strlen(extra + 1);
720 return 0;
723 /* Enough buffer to hold a hexdump of the sprom data. */
724 #define SPROM_BUFFERSIZE 512
726 static int sprom2hex(const u16 *sprom, char *dump)
728 int i, pos = 0;
730 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
731 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
732 "%04X", swab16(sprom[i]) & 0xFFFF);
735 return pos + 1;
738 static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
740 char tmp[5] = { 0 };
741 int cnt = 0;
742 unsigned long parsed;
744 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
745 return -EINVAL;
746 while (cnt < BCM43xx_SPROM_SIZE) {
747 memcpy(tmp, dump, 4);
748 dump += 4;
749 parsed = simple_strtoul(tmp, NULL, 16);
750 sprom[cnt++] = swab16((u16)parsed);
753 return 0;
756 static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
757 struct iw_request_info *info,
758 union iwreq_data *data,
759 char *extra)
761 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
762 int err = -EPERM;
763 u16 *sprom;
764 unsigned long flags;
766 if (!capable(CAP_SYS_RAWIO))
767 goto out;
769 err = -ENOMEM;
770 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
771 GFP_KERNEL);
772 if (!sprom)
773 goto out;
775 mutex_lock(&bcm->mutex);
776 spin_lock_irqsave(&bcm->irq_lock, flags);
777 err = -ENODEV;
778 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
779 err = bcm43xx_sprom_read(bcm, sprom);
780 spin_unlock_irqrestore(&bcm->irq_lock, flags);
781 mutex_unlock(&bcm->mutex);
782 if (!err)
783 data->data.length = sprom2hex(sprom, extra);
784 kfree(sprom);
785 out:
786 return err;
789 static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
790 struct iw_request_info *info,
791 union iwreq_data *data,
792 char *extra)
794 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
795 int err = -EPERM;
796 u16 *sprom;
797 unsigned long flags;
798 char *input;
799 unsigned int len;
801 if (!capable(CAP_SYS_RAWIO))
802 goto out;
804 err = -ENOMEM;
805 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
806 GFP_KERNEL);
807 if (!sprom)
808 goto out;
810 len = data->data.length;
811 extra[len - 1] = '\0';
812 input = strchr(extra, ':');
813 if (input) {
814 input++;
815 len -= input - extra;
816 } else
817 input = extra;
818 err = hex2sprom(sprom, input, len);
819 if (err)
820 goto out_kfree;
822 mutex_lock(&bcm->mutex);
823 spin_lock_irqsave(&bcm->irq_lock, flags);
824 spin_lock(&bcm->leds_lock);
825 err = -ENODEV;
826 if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
827 err = bcm43xx_sprom_write(bcm, sprom);
828 spin_unlock(&bcm->leds_lock);
829 spin_unlock_irqrestore(&bcm->irq_lock, flags);
830 mutex_unlock(&bcm->mutex);
831 out_kfree:
832 kfree(sprom);
833 out:
834 return err;
837 /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
839 static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
841 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
842 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
843 struct iw_statistics *wstats;
844 struct ieee80211_network *network = NULL;
845 static int tmp_level = 0;
846 static int tmp_qual = 0;
847 unsigned long flags;
849 wstats = &bcm->stats.wstats;
850 if (!mac->associated) {
851 wstats->miss.beacon = 0;
852 // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
853 wstats->discard.retries = 0;
854 // bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
855 wstats->discard.nwid = 0;
856 // bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
857 wstats->discard.code = 0;
858 // bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
859 wstats->discard.fragment = 0;
860 wstats->discard.misc = 0;
861 wstats->qual.qual = 0;
862 wstats->qual.level = 0;
863 wstats->qual.noise = 0;
864 wstats->qual.updated = 7;
865 wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
866 return wstats;
868 /* fill in the real statistics when iface associated */
869 spin_lock_irqsave(&mac->ieee->lock, flags);
870 list_for_each_entry(network, &mac->ieee->network_list, list) {
871 if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
872 if (!tmp_level) { /* get initial values */
873 tmp_level = network->stats.signal;
874 tmp_qual = network->stats.rssi;
875 } else { /* smooth results */
876 tmp_level = (15 * tmp_level + network->stats.signal)/16;
877 tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
879 break;
882 spin_unlock_irqrestore(&mac->ieee->lock, flags);
883 wstats->qual.level = tmp_level;
884 wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
885 wstats->qual.noise = bcm->stats.noise;
886 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
887 wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
888 wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
889 wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
890 wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
891 wstats->discard.misc = 0; // FIXME
892 wstats->miss.beacon = 0; // FIXME
893 return wstats;
897 #ifdef WX
898 # undef WX
899 #endif
900 #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
901 static const iw_handler bcm43xx_wx_handlers[] = {
902 /* Wireless Identification */
903 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
904 /* Basic operations */
905 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
906 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
907 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
908 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
909 /* Informative stuff */
910 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
911 /* Access Point manipulation */
912 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
913 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
914 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
915 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
916 /* 802.11 specific support */
917 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
918 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
919 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
920 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
921 /* Other parameters */
922 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
923 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
924 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
925 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
926 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
927 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
928 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
929 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
930 //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
931 //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
932 /* Encoding */
933 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
934 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
935 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
936 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
937 /* Power saving */
938 //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
939 //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
940 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
941 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
942 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
943 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
945 #undef WX
947 static const iw_handler bcm43xx_priv_wx_handlers[] = {
948 /* Set Interference Mitigation Mode. */
949 bcm43xx_wx_set_interfmode,
950 /* Get Interference Mitigation Mode. */
951 bcm43xx_wx_get_interfmode,
952 /* Enable/Disable Short Preamble mode. */
953 bcm43xx_wx_set_shortpreamble,
954 /* Get Short Preamble mode. */
955 bcm43xx_wx_get_shortpreamble,
956 /* Enable/Disable Software Encryption mode */
957 bcm43xx_wx_set_swencryption,
958 /* Get Software Encryption mode */
959 bcm43xx_wx_get_swencryption,
960 /* Write SRPROM data. */
961 bcm43xx_wx_sprom_write,
962 /* Read SPROM data. */
963 bcm43xx_wx_sprom_read,
966 #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
967 #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
968 #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
969 #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
970 #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
971 #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
972 #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
973 #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
975 #define PRIV_WX_DUMMY(ioctl) \
977 .cmd = (ioctl), \
978 .name = "__unused" \
981 static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
983 .cmd = PRIV_WX_SET_INTERFMODE,
984 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
985 .name = "set_interfmode",
988 .cmd = PRIV_WX_GET_INTERFMODE,
989 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
990 .name = "get_interfmode",
993 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
994 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
995 .name = "set_shortpreamb",
998 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
999 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1000 .name = "get_shortpreamb",
1003 .cmd = PRIV_WX_SET_SWENCRYPTION,
1004 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1005 .name = "set_swencrypt",
1008 .cmd = PRIV_WX_GET_SWENCRYPTION,
1009 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1010 .name = "get_swencrypt",
1013 .cmd = PRIV_WX_SPROM_WRITE,
1014 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
1015 .name = "write_sprom",
1018 .cmd = PRIV_WX_SPROM_READ,
1019 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1020 .name = "read_sprom",
1024 const struct iw_handler_def bcm43xx_wx_handlers_def = {
1025 .standard = bcm43xx_wx_handlers,
1026 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
1027 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1028 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
1029 .private = bcm43xx_priv_wx_handlers,
1030 .private_args = bcm43xx_priv_wx_args,
1031 .get_wireless_stats = bcm43xx_get_wireless_stats,