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>
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
51 static int bcm43xx_wx_get_name(struct net_device
*net_dev
,
52 struct iw_request_info
*info
,
53 union iwreq_data
*data
,
56 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
58 struct bcm43xx_phyinfo
*phy
;
59 char suffix
[7] = { 0 };
60 int have_a
= 0, have_b
= 0, have_g
= 0;
62 mutex_lock(&bcm
->mutex
);
63 for (i
= 0; i
< bcm
->nr_80211_available
; i
++) {
64 phy
= &(bcm
->core_80211_ext
[i
].phy
);
66 case BCM43xx_PHYTYPE_A
:
69 case BCM43xx_PHYTYPE_G
:
71 case BCM43xx_PHYTYPE_B
:
78 mutex_unlock(&bcm
->mutex
);
96 snprintf(data
->name
, IFNAMSIZ
, "IEEE 802.11%s", suffix
);
101 static int bcm43xx_wx_set_channelfreq(struct net_device
*net_dev
,
102 struct iw_request_info
*info
,
103 union iwreq_data
*data
,
106 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
112 mutex_lock(&bcm
->mutex
);
113 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
115 if ((data
->freq
.m
>= 0) && (data
->freq
.m
<= 1000)) {
116 channel
= data
->freq
.m
;
117 freq
= bcm43xx_channel_to_freq(bcm
, channel
);
119 channel
= bcm43xx_freq_to_channel(bcm
, data
->freq
.m
);
122 if (!ieee80211_is_valid_channel(bcm
->ieee
, channel
))
124 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
) {
125 //ieee80211softmac_disassoc(softmac, $REASON);
126 bcm43xx_mac_suspend(bcm
);
127 err
= bcm43xx_radio_selectchannel(bcm
, channel
, 0);
128 bcm43xx_mac_enable(bcm
);
130 bcm43xx_current_radio(bcm
)->initial_channel
= channel
;
134 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
135 mutex_unlock(&bcm
->mutex
);
140 static int bcm43xx_wx_get_channelfreq(struct net_device
*net_dev
,
141 struct iw_request_info
*info
,
142 union iwreq_data
*data
,
145 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
146 struct bcm43xx_radioinfo
*radio
;
150 mutex_lock(&bcm
->mutex
);
151 radio
= bcm43xx_current_radio(bcm
);
152 channel
= radio
->channel
;
153 if (channel
== 0xFF) {
154 channel
= radio
->initial_channel
;
158 assert(channel
> 0 && channel
<= 1000);
160 data
->freq
.m
= bcm43xx_channel_to_freq(bcm
, channel
) * 100000;
161 data
->freq
.flags
= 1;
165 mutex_unlock(&bcm
->mutex
);
170 static int bcm43xx_wx_set_mode(struct net_device
*net_dev
,
171 struct iw_request_info
*info
,
172 union iwreq_data
*data
,
175 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
180 if (mode
== IW_MODE_AUTO
)
181 mode
= BCM43xx_INITIAL_IWMODE
;
183 mutex_lock(&bcm
->mutex
);
184 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
185 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
) {
186 if (bcm
->ieee
->iw_mode
!= mode
)
187 bcm43xx_set_iwmode(bcm
, mode
);
189 bcm
->ieee
->iw_mode
= mode
;
190 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
191 mutex_unlock(&bcm
->mutex
);
196 static int bcm43xx_wx_get_mode(struct net_device
*net_dev
,
197 struct iw_request_info
*info
,
198 union iwreq_data
*data
,
201 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
203 mutex_lock(&bcm
->mutex
);
204 data
->mode
= bcm
->ieee
->iw_mode
;
205 mutex_unlock(&bcm
->mutex
);
210 static int bcm43xx_wx_get_rangeparams(struct net_device
*net_dev
,
211 struct iw_request_info
*info
,
212 union iwreq_data
*data
,
215 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
216 struct iw_range
*range
= (struct iw_range
*)extra
;
217 const struct ieee80211_geo
*geo
;
219 struct bcm43xx_phyinfo
*phy
;
221 data
->data
.length
= sizeof(*range
);
222 memset(range
, 0, sizeof(*range
));
224 //TODO: What about 802.11b?
225 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
226 range
->throughput
= 27 * 1000 * 1000;
228 range
->max_qual
.qual
= 100;
229 range
->max_qual
.level
= 146; /* set floor at -110 dBm (146 - 256) */
230 range
->max_qual
.noise
= 146;
231 range
->max_qual
.updated
= IW_QUAL_ALL_UPDATED
;
233 range
->avg_qual
.qual
= 50;
234 range
->avg_qual
.level
= 0;
235 range
->avg_qual
.noise
= 0;
236 range
->avg_qual
.updated
= IW_QUAL_ALL_UPDATED
;
238 range
->min_rts
= BCM43xx_MIN_RTS_THRESHOLD
;
239 range
->max_rts
= BCM43xx_MAX_RTS_THRESHOLD
;
240 range
->min_frag
= MIN_FRAG_THRESHOLD
;
241 range
->max_frag
= MAX_FRAG_THRESHOLD
;
243 range
->encoding_size
[0] = 5;
244 range
->encoding_size
[1] = 13;
245 range
->num_encoding_sizes
= 2;
246 range
->max_encoding_tokens
= WEP_KEYS
;
248 range
->we_version_compiled
= WIRELESS_EXT
;
249 range
->we_version_source
= BCM43xx_WX_VERSION
;
251 range
->enc_capa
= IW_ENC_CAPA_WPA
|
253 IW_ENC_CAPA_CIPHER_TKIP
|
254 IW_ENC_CAPA_CIPHER_CCMP
;
256 mutex_lock(&bcm
->mutex
);
257 phy
= bcm43xx_current_phy(bcm
);
259 range
->num_bitrates
= 0;
261 if (phy
->type
== BCM43xx_PHYTYPE_A
||
262 phy
->type
== BCM43xx_PHYTYPE_G
) {
263 range
->num_bitrates
= 8;
264 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_6MB
;
265 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_9MB
;
266 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_12MB
;
267 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_18MB
;
268 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_24MB
;
269 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_36MB
;
270 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_48MB
;
271 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_54MB
;
273 if (phy
->type
== BCM43xx_PHYTYPE_B
||
274 phy
->type
== BCM43xx_PHYTYPE_G
) {
275 range
->num_bitrates
+= 4;
276 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_1MB
;
277 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_2MB
;
278 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_5MB
;
279 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_11MB
;
282 geo
= ieee80211_get_geo(bcm
->ieee
);
283 range
->num_channels
= geo
->a_channels
+ geo
->bg_channels
;
285 for (i
= 0; i
< geo
->a_channels
; i
++) {
286 if (j
== IW_MAX_FREQUENCIES
)
288 range
->freq
[j
].i
= j
+ 1;
289 range
->freq
[j
].m
= geo
->a
[i
].freq
;//FIXME?
290 range
->freq
[j
].e
= 1;
293 for (i
= 0; i
< geo
->bg_channels
; i
++) {
294 if (j
== IW_MAX_FREQUENCIES
)
296 range
->freq
[j
].i
= j
+ 1;
297 range
->freq
[j
].m
= geo
->bg
[i
].freq
;//FIXME?
298 range
->freq
[j
].e
= 1;
301 range
->num_frequency
= j
;
303 mutex_unlock(&bcm
->mutex
);
308 static int bcm43xx_wx_set_nick(struct net_device
*net_dev
,
309 struct iw_request_info
*info
,
310 union iwreq_data
*data
,
313 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
316 mutex_lock(&bcm
->mutex
);
317 len
= min((size_t)data
->data
.length
, (size_t)IW_ESSID_MAX_SIZE
);
318 memcpy(bcm
->nick
, extra
, len
);
319 bcm
->nick
[len
] = '\0';
320 mutex_unlock(&bcm
->mutex
);
325 static int bcm43xx_wx_get_nick(struct net_device
*net_dev
,
326 struct iw_request_info
*info
,
327 union iwreq_data
*data
,
330 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
333 mutex_lock(&bcm
->mutex
);
334 len
= strlen(bcm
->nick
);
335 memcpy(extra
, bcm
->nick
, len
);
336 data
->data
.length
= (__u16
)len
;
337 data
->data
.flags
= 1;
338 mutex_unlock(&bcm
->mutex
);
343 static int bcm43xx_wx_set_rts(struct net_device
*net_dev
,
344 struct iw_request_info
*info
,
345 union iwreq_data
*data
,
348 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
352 mutex_lock(&bcm
->mutex
);
353 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
354 if (data
->rts
.disabled
) {
355 bcm
->rts_threshold
= BCM43xx_MAX_RTS_THRESHOLD
;
358 if (data
->rts
.value
>= BCM43xx_MIN_RTS_THRESHOLD
&&
359 data
->rts
.value
<= BCM43xx_MAX_RTS_THRESHOLD
) {
360 bcm
->rts_threshold
= data
->rts
.value
;
364 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
365 mutex_unlock(&bcm
->mutex
);
370 static int bcm43xx_wx_get_rts(struct net_device
*net_dev
,
371 struct iw_request_info
*info
,
372 union iwreq_data
*data
,
375 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
377 mutex_lock(&bcm
->mutex
);
378 data
->rts
.value
= bcm
->rts_threshold
;
380 data
->rts
.disabled
= (bcm
->rts_threshold
== BCM43xx_MAX_RTS_THRESHOLD
);
381 mutex_unlock(&bcm
->mutex
);
386 static int bcm43xx_wx_set_frag(struct net_device
*net_dev
,
387 struct iw_request_info
*info
,
388 union iwreq_data
*data
,
391 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
395 mutex_lock(&bcm
->mutex
);
396 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
397 if (data
->frag
.disabled
) {
398 bcm
->ieee
->fts
= MAX_FRAG_THRESHOLD
;
401 if (data
->frag
.value
>= MIN_FRAG_THRESHOLD
&&
402 data
->frag
.value
<= MAX_FRAG_THRESHOLD
) {
403 bcm
->ieee
->fts
= data
->frag
.value
& ~0x1;
407 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
408 mutex_unlock(&bcm
->mutex
);
413 static int bcm43xx_wx_get_frag(struct net_device
*net_dev
,
414 struct iw_request_info
*info
,
415 union iwreq_data
*data
,
418 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
420 mutex_lock(&bcm
->mutex
);
421 data
->frag
.value
= bcm
->ieee
->fts
;
422 data
->frag
.fixed
= 0;
423 data
->frag
.disabled
= (bcm
->ieee
->fts
== MAX_FRAG_THRESHOLD
);
424 mutex_unlock(&bcm
->mutex
);
429 static int bcm43xx_wx_set_xmitpower(struct net_device
*net_dev
,
430 struct iw_request_info
*info
,
431 union iwreq_data
*data
,
434 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
435 struct bcm43xx_radioinfo
*radio
;
436 struct bcm43xx_phyinfo
*phy
;
441 if ((data
->txpower
.flags
& IW_TXPOW_TYPE
) != IW_TXPOW_DBM
) {
442 printk(PFX KERN_ERR
"TX power not in dBm.\n");
446 mutex_lock(&bcm
->mutex
);
447 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
448 if (bcm43xx_status(bcm
) != BCM43xx_STAT_INITIALIZED
)
450 radio
= bcm43xx_current_radio(bcm
);
451 phy
= bcm43xx_current_phy(bcm
);
452 if (data
->txpower
.disabled
!= (!(radio
->enabled
))) {
453 if (data
->txpower
.disabled
)
454 bcm43xx_radio_turn_off(bcm
);
456 bcm43xx_radio_turn_on(bcm
);
458 if (data
->txpower
.value
> 0) {
459 /* desired and maxpower dBm values are in Q5.2 */
460 if (phy
->type
== BCM43xx_PHYTYPE_A
)
461 maxpower
= bcm
->sprom
.maxpower_aphy
;
463 maxpower
= bcm
->sprom
.maxpower_bgphy
;
464 radio
->txpower_desired
= limit_value(data
->txpower
.value
<< 2,
466 bcm43xx_phy_xmitpower(bcm
);
471 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
472 mutex_unlock(&bcm
->mutex
);
477 static int bcm43xx_wx_get_xmitpower(struct net_device
*net_dev
,
478 struct iw_request_info
*info
,
479 union iwreq_data
*data
,
482 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
483 struct bcm43xx_radioinfo
*radio
;
486 mutex_lock(&bcm
->mutex
);
487 if (bcm43xx_status(bcm
) != BCM43xx_STAT_INITIALIZED
)
489 radio
= bcm43xx_current_radio(bcm
);
490 /* desired dBm value is in Q5.2 */
491 data
->txpower
.value
= radio
->txpower_desired
>> 2;
492 data
->txpower
.fixed
= 1;
493 data
->txpower
.flags
= IW_TXPOW_DBM
;
494 data
->txpower
.disabled
= !(radio
->enabled
);
498 mutex_unlock(&bcm
->mutex
);
503 static int bcm43xx_wx_set_encoding(struct net_device
*net_dev
,
504 struct iw_request_info
*info
,
505 union iwreq_data
*data
,
508 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
511 err
= ieee80211_wx_set_encode(bcm
->ieee
, info
, data
, extra
);
516 static int bcm43xx_wx_set_encodingext(struct net_device
*net_dev
,
517 struct iw_request_info
*info
,
518 union iwreq_data
*data
,
521 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
524 err
= ieee80211_wx_set_encodeext(bcm
->ieee
, info
, data
, extra
);
529 static int bcm43xx_wx_get_encoding(struct net_device
*net_dev
,
530 struct iw_request_info
*info
,
531 union iwreq_data
*data
,
534 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
537 err
= ieee80211_wx_get_encode(bcm
->ieee
, info
, data
, extra
);
542 static int bcm43xx_wx_get_encodingext(struct net_device
*net_dev
,
543 struct iw_request_info
*info
,
544 union iwreq_data
*data
,
547 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
550 err
= ieee80211_wx_get_encodeext(bcm
->ieee
, info
, data
, extra
);
555 static int bcm43xx_wx_set_interfmode(struct net_device
*net_dev
,
556 struct iw_request_info
*info
,
557 union iwreq_data
*data
,
560 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
564 mode
= *((int *)extra
);
567 mode
= BCM43xx_RADIO_INTERFMODE_NONE
;
570 mode
= BCM43xx_RADIO_INTERFMODE_NONWLAN
;
573 mode
= BCM43xx_RADIO_INTERFMODE_MANUALWLAN
;
576 mode
= BCM43xx_RADIO_INTERFMODE_AUTOWLAN
;
579 printk(KERN_ERR PFX
"set_interfmode allowed parameters are: "
580 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
585 mutex_lock(&bcm
->mutex
);
586 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
587 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
) {
588 err
= bcm43xx_radio_set_interference_mitigation(bcm
, mode
);
590 printk(KERN_ERR PFX
"Interference Mitigation not "
591 "supported by device\n");
594 if (mode
== BCM43xx_RADIO_INTERFMODE_AUTOWLAN
) {
595 printk(KERN_ERR PFX
"Interference Mitigation mode Auto-WLAN "
596 "not supported while the interface is down.\n");
599 bcm43xx_current_radio(bcm
)->interfmode
= mode
;
601 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
602 mutex_unlock(&bcm
->mutex
);
607 static int bcm43xx_wx_get_interfmode(struct net_device
*net_dev
,
608 struct iw_request_info
*info
,
609 union iwreq_data
*data
,
612 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
615 mutex_lock(&bcm
->mutex
);
616 mode
= bcm43xx_current_radio(bcm
)->interfmode
;
617 mutex_unlock(&bcm
->mutex
);
620 case BCM43xx_RADIO_INTERFMODE_NONE
:
621 strncpy(extra
, "0 (No Interference Mitigation)", MAX_WX_STRING
);
623 case BCM43xx_RADIO_INTERFMODE_NONWLAN
:
624 strncpy(extra
, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING
);
626 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN
:
627 strncpy(extra
, "2 (WLAN Interference Mitigation)", MAX_WX_STRING
);
632 data
->data
.length
= strlen(extra
) + 1;
637 static int bcm43xx_wx_set_shortpreamble(struct net_device
*net_dev
,
638 struct iw_request_info
*info
,
639 union iwreq_data
*data
,
642 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
646 on
= *((int *)extra
);
647 mutex_lock(&bcm
->mutex
);
648 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
649 bcm
->short_preamble
= !!on
;
650 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
651 mutex_unlock(&bcm
->mutex
);
656 static int bcm43xx_wx_get_shortpreamble(struct net_device
*net_dev
,
657 struct iw_request_info
*info
,
658 union iwreq_data
*data
,
661 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
664 mutex_lock(&bcm
->mutex
);
665 on
= bcm
->short_preamble
;
666 mutex_unlock(&bcm
->mutex
);
669 strncpy(extra
, "1 (Short Preamble enabled)", MAX_WX_STRING
);
671 strncpy(extra
, "0 (Short Preamble disabled)", MAX_WX_STRING
);
672 data
->data
.length
= strlen(extra
) + 1;
677 static int bcm43xx_wx_set_swencryption(struct net_device
*net_dev
,
678 struct iw_request_info
*info
,
679 union iwreq_data
*data
,
682 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
686 on
= *((int *)extra
);
688 mutex_lock(&bcm
->mutex
);
689 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
690 bcm
->ieee
->host_encrypt
= !!on
;
691 bcm
->ieee
->host_decrypt
= !!on
;
692 bcm
->ieee
->host_build_iv
= !on
;
693 bcm
->ieee
->host_strip_iv_icv
= !on
;
694 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
695 mutex_unlock(&bcm
->mutex
);
700 static int bcm43xx_wx_get_swencryption(struct net_device
*net_dev
,
701 struct iw_request_info
*info
,
702 union iwreq_data
*data
,
705 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
708 mutex_lock(&bcm
->mutex
);
709 on
= bcm
->ieee
->host_encrypt
;
710 mutex_unlock(&bcm
->mutex
);
713 strncpy(extra
, "1 (SW encryption enabled) ", MAX_WX_STRING
);
715 strncpy(extra
, "0 (SW encryption disabled) ", MAX_WX_STRING
);
716 data
->data
.length
= strlen(extra
+ 1);
721 /* Enough buffer to hold a hexdump of the sprom data. */
722 #define SPROM_BUFFERSIZE 512
724 static int sprom2hex(const u16
*sprom
, char *dump
)
728 for (i
= 0; i
< BCM43xx_SPROM_SIZE
; i
++) {
729 pos
+= snprintf(dump
+ pos
, SPROM_BUFFERSIZE
- pos
- 1,
730 "%04X", swab16(sprom
[i
]) & 0xFFFF);
736 static int hex2sprom(u16
*sprom
, const char *dump
, unsigned int len
)
740 unsigned long parsed
;
742 if (len
< BCM43xx_SPROM_SIZE
* sizeof(u16
) * 2)
744 while (cnt
< BCM43xx_SPROM_SIZE
) {
745 memcpy(tmp
, dump
, 4);
747 parsed
= simple_strtoul(tmp
, NULL
, 16);
748 sprom
[cnt
++] = swab16((u16
)parsed
);
754 static int bcm43xx_wx_sprom_read(struct net_device
*net_dev
,
755 struct iw_request_info
*info
,
756 union iwreq_data
*data
,
759 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
764 if (!capable(CAP_SYS_RAWIO
))
768 sprom
= kmalloc(BCM43xx_SPROM_SIZE
* sizeof(*sprom
),
773 mutex_lock(&bcm
->mutex
);
774 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
776 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
)
777 err
= bcm43xx_sprom_read(bcm
, sprom
);
778 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
779 mutex_unlock(&bcm
->mutex
);
781 data
->data
.length
= sprom2hex(sprom
, extra
);
787 static int bcm43xx_wx_sprom_write(struct net_device
*net_dev
,
788 struct iw_request_info
*info
,
789 union iwreq_data
*data
,
792 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
799 if (!capable(CAP_SYS_RAWIO
))
803 sprom
= kmalloc(BCM43xx_SPROM_SIZE
* sizeof(*sprom
),
808 len
= data
->data
.length
;
809 extra
[len
- 1] = '\0';
810 input
= strchr(extra
, ':');
813 len
-= input
- extra
;
816 err
= hex2sprom(sprom
, input
, len
);
820 mutex_lock(&bcm
->mutex
);
821 spin_lock_irqsave(&bcm
->irq_lock
, flags
);
822 spin_lock(&bcm
->leds_lock
);
824 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
)
825 err
= bcm43xx_sprom_write(bcm
, sprom
);
826 spin_unlock(&bcm
->leds_lock
);
827 spin_unlock_irqrestore(&bcm
->irq_lock
, flags
);
828 mutex_unlock(&bcm
->mutex
);
835 /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
837 static struct iw_statistics
*bcm43xx_get_wireless_stats(struct net_device
*net_dev
)
839 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
840 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
841 struct iw_statistics
*wstats
;
842 struct ieee80211_network
*network
= NULL
;
843 static int tmp_level
= 0;
844 static int tmp_qual
= 0;
847 wstats
= &bcm
->stats
.wstats
;
848 if (!mac
->associnfo
.associated
) {
849 wstats
->miss
.beacon
= 0;
850 // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
851 wstats
->discard
.retries
= 0;
852 // bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
853 wstats
->discard
.nwid
= 0;
854 // bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
855 wstats
->discard
.code
= 0;
856 // bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
857 wstats
->discard
.fragment
= 0;
858 wstats
->discard
.misc
= 0;
859 wstats
->qual
.qual
= 0;
860 wstats
->qual
.level
= 0;
861 wstats
->qual
.noise
= 0;
862 wstats
->qual
.updated
= 7;
863 wstats
->qual
.updated
|= IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
866 /* fill in the real statistics when iface associated */
867 spin_lock_irqsave(&mac
->ieee
->lock
, flags
);
868 list_for_each_entry(network
, &mac
->ieee
->network_list
, list
) {
869 if (!memcmp(mac
->associnfo
.bssid
, network
->bssid
, ETH_ALEN
)) {
870 if (!tmp_level
) { /* get initial values */
871 tmp_level
= network
->stats
.signal
;
872 tmp_qual
= network
->stats
.rssi
;
873 } else { /* smooth results */
874 tmp_level
= (15 * tmp_level
+ network
->stats
.signal
)/16;
875 tmp_qual
= (15 * tmp_qual
+ network
->stats
.rssi
)/16;
880 spin_unlock_irqrestore(&mac
->ieee
->lock
, flags
);
881 wstats
->qual
.level
= tmp_level
;
882 wstats
->qual
.qual
= 100 * tmp_qual
/ RX_RSSI_MAX
;
883 wstats
->qual
.noise
= bcm
->stats
.noise
;
884 wstats
->qual
.updated
= IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
885 wstats
->discard
.code
= bcm
->ieee
->ieee_stats
.rx_discards_undecryptable
;
886 wstats
->discard
.retries
= bcm
->ieee
->ieee_stats
.tx_retry_limit_exceeded
;
887 wstats
->discard
.nwid
= bcm
->ieee
->ieee_stats
.tx_discards_wrong_sa
;
888 wstats
->discard
.fragment
= bcm
->ieee
->ieee_stats
.rx_fragments
;
889 wstats
->discard
.misc
= 0; // FIXME
890 wstats
->miss
.beacon
= 0; // FIXME
898 #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
899 static const iw_handler bcm43xx_wx_handlers
[] = {
900 /* Wireless Identification */
901 WX(SIOCGIWNAME
) = bcm43xx_wx_get_name
,
902 /* Basic operations */
903 WX(SIOCSIWFREQ
) = bcm43xx_wx_set_channelfreq
,
904 WX(SIOCGIWFREQ
) = bcm43xx_wx_get_channelfreq
,
905 WX(SIOCSIWMODE
) = bcm43xx_wx_set_mode
,
906 WX(SIOCGIWMODE
) = bcm43xx_wx_get_mode
,
907 /* Informative stuff */
908 WX(SIOCGIWRANGE
) = bcm43xx_wx_get_rangeparams
,
909 /* Access Point manipulation */
910 WX(SIOCSIWAP
) = ieee80211softmac_wx_set_wap
,
911 WX(SIOCGIWAP
) = ieee80211softmac_wx_get_wap
,
912 WX(SIOCSIWSCAN
) = ieee80211softmac_wx_trigger_scan
,
913 WX(SIOCGIWSCAN
) = ieee80211softmac_wx_get_scan_results
,
914 /* 802.11 specific support */
915 WX(SIOCSIWESSID
) = ieee80211softmac_wx_set_essid
,
916 WX(SIOCGIWESSID
) = ieee80211softmac_wx_get_essid
,
917 WX(SIOCSIWNICKN
) = bcm43xx_wx_set_nick
,
918 WX(SIOCGIWNICKN
) = bcm43xx_wx_get_nick
,
919 /* Other parameters */
920 WX(SIOCSIWRATE
) = ieee80211softmac_wx_set_rate
,
921 WX(SIOCGIWRATE
) = ieee80211softmac_wx_get_rate
,
922 WX(SIOCSIWRTS
) = bcm43xx_wx_set_rts
,
923 WX(SIOCGIWRTS
) = bcm43xx_wx_get_rts
,
924 WX(SIOCSIWFRAG
) = bcm43xx_wx_set_frag
,
925 WX(SIOCGIWFRAG
) = bcm43xx_wx_get_frag
,
926 WX(SIOCSIWTXPOW
) = bcm43xx_wx_set_xmitpower
,
927 WX(SIOCGIWTXPOW
) = bcm43xx_wx_get_xmitpower
,
928 //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
929 //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
931 WX(SIOCSIWENCODE
) = bcm43xx_wx_set_encoding
,
932 WX(SIOCGIWENCODE
) = bcm43xx_wx_get_encoding
,
933 WX(SIOCSIWENCODEEXT
) = bcm43xx_wx_set_encodingext
,
934 WX(SIOCGIWENCODEEXT
) = bcm43xx_wx_get_encodingext
,
936 //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
937 //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
938 WX(SIOCSIWGENIE
) = ieee80211softmac_wx_set_genie
,
939 WX(SIOCGIWGENIE
) = ieee80211softmac_wx_get_genie
,
940 WX(SIOCSIWAUTH
) = ieee80211_wx_set_auth
,
941 WX(SIOCGIWAUTH
) = ieee80211_wx_get_auth
,
945 static const iw_handler bcm43xx_priv_wx_handlers
[] = {
946 /* Set Interference Mitigation Mode. */
947 bcm43xx_wx_set_interfmode
,
948 /* Get Interference Mitigation Mode. */
949 bcm43xx_wx_get_interfmode
,
950 /* Enable/Disable Short Preamble mode. */
951 bcm43xx_wx_set_shortpreamble
,
952 /* Get Short Preamble mode. */
953 bcm43xx_wx_get_shortpreamble
,
954 /* Enable/Disable Software Encryption mode */
955 bcm43xx_wx_set_swencryption
,
956 /* Get Software Encryption mode */
957 bcm43xx_wx_get_swencryption
,
958 /* Write SRPROM data. */
959 bcm43xx_wx_sprom_write
,
960 /* Read SPROM data. */
961 bcm43xx_wx_sprom_read
,
964 #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
965 #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
966 #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
967 #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
968 #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
969 #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
970 #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
971 #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
973 #define PRIV_WX_DUMMY(ioctl) \
979 static const struct iw_priv_args bcm43xx_priv_wx_args
[] = {
981 .cmd
= PRIV_WX_SET_INTERFMODE
,
982 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
983 .name
= "set_interfmode",
986 .cmd
= PRIV_WX_GET_INTERFMODE
,
987 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
988 .name
= "get_interfmode",
991 .cmd
= PRIV_WX_SET_SHORTPREAMBLE
,
992 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
993 .name
= "set_shortpreamb",
996 .cmd
= PRIV_WX_GET_SHORTPREAMBLE
,
997 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
998 .name
= "get_shortpreamb",
1001 .cmd
= PRIV_WX_SET_SWENCRYPTION
,
1002 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
1003 .name
= "set_swencrypt",
1006 .cmd
= PRIV_WX_GET_SWENCRYPTION
,
1007 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
1008 .name
= "get_swencrypt",
1011 .cmd
= PRIV_WX_SPROM_WRITE
,
1012 .set_args
= IW_PRIV_TYPE_CHAR
| SPROM_BUFFERSIZE
,
1013 .name
= "write_sprom",
1016 .cmd
= PRIV_WX_SPROM_READ
,
1017 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| SPROM_BUFFERSIZE
,
1018 .name
= "read_sprom",
1022 const struct iw_handler_def bcm43xx_wx_handlers_def
= {
1023 .standard
= bcm43xx_wx_handlers
,
1024 .num_standard
= ARRAY_SIZE(bcm43xx_wx_handlers
),
1025 .num_private
= ARRAY_SIZE(bcm43xx_priv_wx_handlers
),
1026 .num_private_args
= ARRAY_SIZE(bcm43xx_priv_wx_args
),
1027 .private = bcm43xx_priv_wx_handlers
,
1028 .private_args
= bcm43xx_priv_wx_args
,
1029 .get_wireless_stats
= bcm43xx_get_wireless_stats
,