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
52 static int bcm43xx_wx_get_name(struct net_device
*net_dev
,
53 struct iw_request_info
*info
,
54 union iwreq_data
*data
,
57 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
60 struct bcm43xx_phyinfo
*phy
;
61 char suffix
[7] = { 0 };
62 int have_a
= 0, have_b
= 0, have_g
= 0;
64 bcm43xx_lock_irqsafe(bcm
, flags
);
65 for (i
= 0; i
< bcm
->nr_80211_available
; i
++) {
66 phy
= &(bcm
->core_80211_ext
[i
].phy
);
68 case BCM43xx_PHYTYPE_A
:
71 case BCM43xx_PHYTYPE_G
:
73 case BCM43xx_PHYTYPE_B
:
80 bcm43xx_unlock_irqsafe(bcm
, flags
);
98 snprintf(data
->name
, IFNAMSIZ
, "IEEE 802.11%s", suffix
);
103 static int bcm43xx_wx_set_channelfreq(struct net_device
*net_dev
,
104 struct iw_request_info
*info
,
105 union iwreq_data
*data
,
108 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
114 bcm43xx_lock_irqsafe(bcm
, 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 bcm43xx_unlock_irqsafe(bcm
, flags
);
139 static int bcm43xx_wx_get_channelfreq(struct net_device
*net_dev
,
140 struct iw_request_info
*info
,
141 union iwreq_data
*data
,
144 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
145 struct bcm43xx_radioinfo
*radio
;
150 bcm43xx_lock_irqsafe(bcm
, flags
);
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 bcm43xx_unlock_irqsafe(bcm
, flags
);
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 bcm43xx_lock_irqsafe(bcm
, flags
);
184 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
) {
185 if (bcm
->ieee
->iw_mode
!= mode
)
186 bcm43xx_set_iwmode(bcm
, mode
);
188 bcm
->ieee
->iw_mode
= mode
;
189 bcm43xx_unlock_irqsafe(bcm
, flags
);
194 static int bcm43xx_wx_get_mode(struct net_device
*net_dev
,
195 struct iw_request_info
*info
,
196 union iwreq_data
*data
,
199 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
202 bcm43xx_lock_irqsafe(bcm
, flags
);
203 data
->mode
= bcm
->ieee
->iw_mode
;
204 bcm43xx_unlock_irqsafe(bcm
, flags
);
209 static int bcm43xx_wx_get_rangeparams(struct net_device
*net_dev
,
210 struct iw_request_info
*info
,
211 union iwreq_data
*data
,
214 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
215 struct iw_range
*range
= (struct iw_range
*)extra
;
216 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 /* TODO: Real max RSSI */
230 range
->max_qual
.level
= 3;
231 range
->max_qual
.noise
= 100;
232 range
->max_qual
.updated
= 7;
234 range
->avg_qual
.qual
= 70;
235 range
->avg_qual
.level
= 2;
236 range
->avg_qual
.noise
= 40;
237 range
->avg_qual
.updated
= 7;
239 range
->min_rts
= BCM43xx_MIN_RTS_THRESHOLD
;
240 range
->max_rts
= BCM43xx_MAX_RTS_THRESHOLD
;
241 range
->min_frag
= MIN_FRAG_THRESHOLD
;
242 range
->max_frag
= MAX_FRAG_THRESHOLD
;
244 range
->encoding_size
[0] = 5;
245 range
->encoding_size
[1] = 13;
246 range
->num_encoding_sizes
= 2;
247 range
->max_encoding_tokens
= WEP_KEYS
;
249 range
->we_version_compiled
= WIRELESS_EXT
;
250 range
->we_version_source
= BCM43xx_WX_VERSION
;
252 range
->enc_capa
= IW_ENC_CAPA_WPA
|
254 IW_ENC_CAPA_CIPHER_TKIP
|
255 IW_ENC_CAPA_CIPHER_CCMP
;
257 bcm43xx_lock_irqsafe(bcm
, flags
);
258 phy
= bcm43xx_current_phy(bcm
);
260 range
->num_bitrates
= 0;
262 if (phy
->type
== BCM43xx_PHYTYPE_A
||
263 phy
->type
== BCM43xx_PHYTYPE_G
) {
264 range
->num_bitrates
= 8;
265 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_6MB
;
266 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_9MB
;
267 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_12MB
;
268 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_18MB
;
269 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_24MB
;
270 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_36MB
;
271 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_48MB
;
272 range
->bitrate
[i
++] = IEEE80211_OFDM_RATE_54MB
;
274 if (phy
->type
== BCM43xx_PHYTYPE_B
||
275 phy
->type
== BCM43xx_PHYTYPE_G
) {
276 range
->num_bitrates
+= 4;
277 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_1MB
;
278 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_2MB
;
279 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_5MB
;
280 range
->bitrate
[i
++] = IEEE80211_CCK_RATE_11MB
;
283 geo
= ieee80211_get_geo(bcm
->ieee
);
284 range
->num_channels
= geo
->a_channels
+ geo
->bg_channels
;
286 for (i
= 0; i
< geo
->a_channels
; i
++) {
287 if (j
== IW_MAX_FREQUENCIES
)
289 range
->freq
[j
].i
= j
+ 1;
290 range
->freq
[j
].m
= geo
->a
[i
].freq
;//FIXME?
291 range
->freq
[j
].e
= 1;
294 for (i
= 0; i
< geo
->bg_channels
; i
++) {
295 if (j
== IW_MAX_FREQUENCIES
)
297 range
->freq
[j
].i
= j
+ 1;
298 range
->freq
[j
].m
= geo
->bg
[i
].freq
;//FIXME?
299 range
->freq
[j
].e
= 1;
302 range
->num_frequency
= j
;
304 bcm43xx_unlock_irqsafe(bcm
, flags
);
309 static int bcm43xx_wx_set_nick(struct net_device
*net_dev
,
310 struct iw_request_info
*info
,
311 union iwreq_data
*data
,
314 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
317 bcm43xx_lock_noirq(bcm
);
318 len
= min((size_t)data
->data
.length
, (size_t)IW_ESSID_MAX_SIZE
);
319 memcpy(bcm
->nick
, extra
, len
);
320 bcm
->nick
[len
] = '\0';
321 bcm43xx_unlock_noirq(bcm
);
326 static int bcm43xx_wx_get_nick(struct net_device
*net_dev
,
327 struct iw_request_info
*info
,
328 union iwreq_data
*data
,
331 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
334 bcm43xx_lock_noirq(bcm
);
335 len
= strlen(bcm
->nick
) + 1;
336 memcpy(extra
, bcm
->nick
, len
);
337 data
->data
.length
= (__u16
)len
;
338 data
->data
.flags
= 1;
339 bcm43xx_unlock_noirq(bcm
);
344 static int bcm43xx_wx_set_rts(struct net_device
*net_dev
,
345 struct iw_request_info
*info
,
346 union iwreq_data
*data
,
349 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
353 bcm43xx_lock_irqsafe(bcm
, 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 bcm43xx_unlock_irqsafe(bcm
, flags
);
369 static int bcm43xx_wx_get_rts(struct net_device
*net_dev
,
370 struct iw_request_info
*info
,
371 union iwreq_data
*data
,
374 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
377 bcm43xx_lock_irqsafe(bcm
, flags
);
378 data
->rts
.value
= bcm
->rts_threshold
;
380 data
->rts
.disabled
= (bcm
->rts_threshold
== BCM43xx_MAX_RTS_THRESHOLD
);
381 bcm43xx_unlock_irqsafe(bcm
, flags
);
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 bcm43xx_lock_irqsafe(bcm
, flags
);
396 if (data
->frag
.disabled
) {
397 bcm
->ieee
->fts
= MAX_FRAG_THRESHOLD
;
400 if (data
->frag
.value
>= MIN_FRAG_THRESHOLD
&&
401 data
->frag
.value
<= MAX_FRAG_THRESHOLD
) {
402 bcm
->ieee
->fts
= data
->frag
.value
& ~0x1;
406 bcm43xx_unlock_irqsafe(bcm
, flags
);
411 static int bcm43xx_wx_get_frag(struct net_device
*net_dev
,
412 struct iw_request_info
*info
,
413 union iwreq_data
*data
,
416 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
419 bcm43xx_lock_irqsafe(bcm
, flags
);
420 data
->frag
.value
= bcm
->ieee
->fts
;
421 data
->frag
.fixed
= 0;
422 data
->frag
.disabled
= (bcm
->ieee
->fts
== MAX_FRAG_THRESHOLD
);
423 bcm43xx_unlock_irqsafe(bcm
, flags
);
428 static int bcm43xx_wx_set_xmitpower(struct net_device
*net_dev
,
429 struct iw_request_info
*info
,
430 union iwreq_data
*data
,
433 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
434 struct bcm43xx_radioinfo
*radio
;
435 struct bcm43xx_phyinfo
*phy
;
440 if ((data
->txpower
.flags
& IW_TXPOW_TYPE
) != IW_TXPOW_DBM
) {
441 printk(PFX KERN_ERR
"TX power not in dBm.\n");
445 bcm43xx_lock_irqsafe(bcm
, flags
);
446 if (bcm43xx_status(bcm
) != BCM43xx_STAT_INITIALIZED
)
448 radio
= bcm43xx_current_radio(bcm
);
449 phy
= bcm43xx_current_phy(bcm
);
450 if (data
->txpower
.disabled
!= (!(radio
->enabled
))) {
451 if (data
->txpower
.disabled
)
452 bcm43xx_radio_turn_off(bcm
);
454 bcm43xx_radio_turn_on(bcm
);
456 if (data
->txpower
.value
> 0) {
457 /* desired and maxpower dBm values are in Q5.2 */
458 if (phy
->type
== BCM43xx_PHYTYPE_A
)
459 maxpower
= bcm
->sprom
.maxpower_aphy
;
461 maxpower
= bcm
->sprom
.maxpower_bgphy
;
462 radio
->txpower_desired
= limit_value(data
->txpower
.value
<< 2,
464 bcm43xx_phy_xmitpower(bcm
);
469 bcm43xx_unlock_irqsafe(bcm
, flags
);
474 static int bcm43xx_wx_get_xmitpower(struct net_device
*net_dev
,
475 struct iw_request_info
*info
,
476 union iwreq_data
*data
,
479 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
480 struct bcm43xx_radioinfo
*radio
;
484 bcm43xx_lock_irqsafe(bcm
, flags
);
485 if (bcm43xx_status(bcm
) != BCM43xx_STAT_INITIALIZED
)
487 radio
= bcm43xx_current_radio(bcm
);
488 /* desired dBm value is in Q5.2 */
489 data
->txpower
.value
= radio
->txpower_desired
>> 2;
490 data
->txpower
.fixed
= 1;
491 data
->txpower
.flags
= IW_TXPOW_DBM
;
492 data
->txpower
.disabled
= !(radio
->enabled
);
496 bcm43xx_unlock_irqsafe(bcm
, flags
);
501 static int bcm43xx_wx_set_encoding(struct net_device
*net_dev
,
502 struct iw_request_info
*info
,
503 union iwreq_data
*data
,
506 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
509 err
= ieee80211_wx_set_encode(bcm
->ieee
, info
, data
, extra
);
514 static int bcm43xx_wx_set_encodingext(struct net_device
*net_dev
,
515 struct iw_request_info
*info
,
516 union iwreq_data
*data
,
519 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
522 err
= ieee80211_wx_set_encodeext(bcm
->ieee
, info
, data
, extra
);
527 static int bcm43xx_wx_get_encoding(struct net_device
*net_dev
,
528 struct iw_request_info
*info
,
529 union iwreq_data
*data
,
532 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
535 err
= ieee80211_wx_get_encode(bcm
->ieee
, info
, data
, extra
);
540 static int bcm43xx_wx_get_encodingext(struct net_device
*net_dev
,
541 struct iw_request_info
*info
,
542 union iwreq_data
*data
,
545 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
548 err
= ieee80211_wx_get_encodeext(bcm
->ieee
, info
, data
, extra
);
553 static int bcm43xx_wx_set_interfmode(struct net_device
*net_dev
,
554 struct iw_request_info
*info
,
555 union iwreq_data
*data
,
558 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
562 mode
= *((int *)extra
);
565 mode
= BCM43xx_RADIO_INTERFMODE_NONE
;
568 mode
= BCM43xx_RADIO_INTERFMODE_NONWLAN
;
571 mode
= BCM43xx_RADIO_INTERFMODE_MANUALWLAN
;
574 mode
= BCM43xx_RADIO_INTERFMODE_AUTOWLAN
;
577 printk(KERN_ERR PFX
"set_interfmode allowed parameters are: "
578 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
583 bcm43xx_lock_irqsafe(bcm
, flags
);
584 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
) {
585 err
= bcm43xx_radio_set_interference_mitigation(bcm
, mode
);
587 printk(KERN_ERR PFX
"Interference Mitigation not "
588 "supported by device\n");
591 if (mode
== BCM43xx_RADIO_INTERFMODE_AUTOWLAN
) {
592 printk(KERN_ERR PFX
"Interference Mitigation mode Auto-WLAN "
593 "not supported while the interface is down.\n");
596 bcm43xx_current_radio(bcm
)->interfmode
= mode
;
598 bcm43xx_unlock_irqsafe(bcm
, flags
);
603 static int bcm43xx_wx_get_interfmode(struct net_device
*net_dev
,
604 struct iw_request_info
*info
,
605 union iwreq_data
*data
,
608 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
612 bcm43xx_lock_irqsafe(bcm
, flags
);
613 mode
= bcm43xx_current_radio(bcm
)->interfmode
;
614 bcm43xx_unlock_irqsafe(bcm
, flags
);
617 case BCM43xx_RADIO_INTERFMODE_NONE
:
618 strncpy(extra
, "0 (No Interference Mitigation)", MAX_WX_STRING
);
620 case BCM43xx_RADIO_INTERFMODE_NONWLAN
:
621 strncpy(extra
, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING
);
623 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN
:
624 strncpy(extra
, "2 (WLAN Interference Mitigation)", MAX_WX_STRING
);
629 data
->data
.length
= strlen(extra
) + 1;
634 static int bcm43xx_wx_set_shortpreamble(struct net_device
*net_dev
,
635 struct iw_request_info
*info
,
636 union iwreq_data
*data
,
639 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
643 on
= *((int *)extra
);
644 bcm43xx_lock_irqsafe(bcm
, flags
);
645 bcm
->short_preamble
= !!on
;
646 bcm43xx_unlock_irqsafe(bcm
, flags
);
651 static int bcm43xx_wx_get_shortpreamble(struct net_device
*net_dev
,
652 struct iw_request_info
*info
,
653 union iwreq_data
*data
,
656 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
660 bcm43xx_lock_irqsafe(bcm
, flags
);
661 on
= bcm
->short_preamble
;
662 bcm43xx_unlock_irqsafe(bcm
, flags
);
665 strncpy(extra
, "1 (Short Preamble enabled)", MAX_WX_STRING
);
667 strncpy(extra
, "0 (Short Preamble disabled)", MAX_WX_STRING
);
668 data
->data
.length
= strlen(extra
) + 1;
673 static int bcm43xx_wx_set_swencryption(struct net_device
*net_dev
,
674 struct iw_request_info
*info
,
675 union iwreq_data
*data
,
678 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
682 on
= *((int *)extra
);
684 bcm43xx_lock_irqsafe(bcm
, flags
);
685 bcm
->ieee
->host_encrypt
= !!on
;
686 bcm
->ieee
->host_decrypt
= !!on
;
687 bcm
->ieee
->host_build_iv
= !on
;
688 bcm43xx_unlock_irqsafe(bcm
, flags
);
693 static int bcm43xx_wx_get_swencryption(struct net_device
*net_dev
,
694 struct iw_request_info
*info
,
695 union iwreq_data
*data
,
698 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
702 bcm43xx_lock_irqsafe(bcm
, flags
);
703 on
= bcm
->ieee
->host_encrypt
;
704 bcm43xx_unlock_irqsafe(bcm
, flags
);
707 strncpy(extra
, "1 (SW encryption enabled) ", MAX_WX_STRING
);
709 strncpy(extra
, "0 (SW encryption disabled) ", MAX_WX_STRING
);
710 data
->data
.length
= strlen(extra
+ 1);
715 /* Enough buffer to hold a hexdump of the sprom data. */
716 #define SPROM_BUFFERSIZE 512
718 static int sprom2hex(const u16
*sprom
, char *dump
)
722 for (i
= 0; i
< BCM43xx_SPROM_SIZE
; i
++) {
723 pos
+= snprintf(dump
+ pos
, SPROM_BUFFERSIZE
- pos
- 1,
724 "%04X", swab16(sprom
[i
]) & 0xFFFF);
730 static int hex2sprom(u16
*sprom
, const char *dump
, unsigned int len
)
734 unsigned long parsed
;
736 if (len
< BCM43xx_SPROM_SIZE
* sizeof(u16
) * 2)
738 while (cnt
< BCM43xx_SPROM_SIZE
) {
739 memcpy(tmp
, dump
, 4);
741 parsed
= simple_strtoul(tmp
, NULL
, 16);
742 sprom
[cnt
++] = swab16((u16
)parsed
);
748 static int bcm43xx_wx_sprom_read(struct net_device
*net_dev
,
749 struct iw_request_info
*info
,
750 union iwreq_data
*data
,
753 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
758 if (!capable(CAP_SYS_RAWIO
))
762 sprom
= kmalloc(BCM43xx_SPROM_SIZE
* sizeof(*sprom
),
767 bcm43xx_lock_irqsafe(bcm
, flags
);
769 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
)
770 err
= bcm43xx_sprom_read(bcm
, sprom
);
771 bcm43xx_unlock_irqsafe(bcm
, flags
);
773 data
->data
.length
= sprom2hex(sprom
, extra
);
779 static int bcm43xx_wx_sprom_write(struct net_device
*net_dev
,
780 struct iw_request_info
*info
,
781 union iwreq_data
*data
,
784 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
791 if (!capable(CAP_SYS_RAWIO
))
795 sprom
= kmalloc(BCM43xx_SPROM_SIZE
* sizeof(*sprom
),
800 len
= data
->data
.length
;
801 extra
[len
- 1] = '\0';
802 input
= strchr(extra
, ':');
805 len
-= input
- extra
;
808 err
= hex2sprom(sprom
, input
, len
);
812 bcm43xx_lock_irqsafe(bcm
, flags
);
814 if (bcm43xx_status(bcm
) == BCM43xx_STAT_INITIALIZED
)
815 err
= bcm43xx_sprom_write(bcm
, sprom
);
816 bcm43xx_unlock_irqsafe(bcm
, flags
);
823 /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
825 static struct iw_statistics
*bcm43xx_get_wireless_stats(struct net_device
*net_dev
)
827 struct bcm43xx_private
*bcm
= bcm43xx_priv(net_dev
);
828 struct ieee80211softmac_device
*mac
= ieee80211_priv(net_dev
);
829 struct iw_statistics
*wstats
;
831 wstats
= &bcm
->stats
.wstats
;
832 if (!mac
->associated
) {
833 wstats
->miss
.beacon
= 0;
834 // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
835 wstats
->discard
.retries
= 0;
836 // bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
837 wstats
->discard
.nwid
= 0;
838 // bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
839 wstats
->discard
.code
= 0;
840 // bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
841 wstats
->discard
.fragment
= 0;
842 wstats
->discard
.misc
= 0;
843 wstats
->qual
.qual
= 0;
844 wstats
->qual
.level
= 0;
845 wstats
->qual
.noise
= 0;
846 wstats
->qual
.updated
= 7;
847 wstats
->qual
.updated
|= IW_QUAL_NOISE_INVALID
|
848 IW_QUAL_QUAL_INVALID
| IW_QUAL_LEVEL_INVALID
;
851 /* fill in the real statistics when iface associated */
852 wstats
->qual
.qual
= 100; // TODO: get the real signal quality
853 wstats
->qual
.level
= 3 - bcm
->stats
.link_quality
;
854 wstats
->qual
.noise
= bcm
->stats
.noise
;
855 wstats
->qual
.updated
= IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
|
856 IW_QUAL_NOISE_UPDATED
;
857 wstats
->discard
.code
= bcm
->ieee
->ieee_stats
.rx_discards_undecryptable
;
858 wstats
->discard
.retries
= bcm
->ieee
->ieee_stats
.tx_retry_limit_exceeded
;
859 wstats
->discard
.nwid
= bcm
->ieee
->ieee_stats
.tx_discards_wrong_sa
;
860 wstats
->discard
.fragment
= bcm
->ieee
->ieee_stats
.rx_fragments
;
861 wstats
->discard
.misc
= 0; // FIXME
862 wstats
->miss
.beacon
= 0; // FIXME
870 #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
871 static const iw_handler bcm43xx_wx_handlers
[] = {
872 /* Wireless Identification */
873 WX(SIOCGIWNAME
) = bcm43xx_wx_get_name
,
874 /* Basic operations */
875 WX(SIOCSIWFREQ
) = bcm43xx_wx_set_channelfreq
,
876 WX(SIOCGIWFREQ
) = bcm43xx_wx_get_channelfreq
,
877 WX(SIOCSIWMODE
) = bcm43xx_wx_set_mode
,
878 WX(SIOCGIWMODE
) = bcm43xx_wx_get_mode
,
879 /* Informative stuff */
880 WX(SIOCGIWRANGE
) = bcm43xx_wx_get_rangeparams
,
881 /* Access Point manipulation */
882 WX(SIOCSIWAP
) = ieee80211softmac_wx_set_wap
,
883 WX(SIOCGIWAP
) = ieee80211softmac_wx_get_wap
,
884 WX(SIOCSIWSCAN
) = ieee80211softmac_wx_trigger_scan
,
885 WX(SIOCGIWSCAN
) = ieee80211softmac_wx_get_scan_results
,
886 /* 802.11 specific support */
887 WX(SIOCSIWESSID
) = ieee80211softmac_wx_set_essid
,
888 WX(SIOCGIWESSID
) = ieee80211softmac_wx_get_essid
,
889 WX(SIOCSIWNICKN
) = bcm43xx_wx_set_nick
,
890 WX(SIOCGIWNICKN
) = bcm43xx_wx_get_nick
,
891 /* Other parameters */
892 WX(SIOCSIWRATE
) = ieee80211softmac_wx_set_rate
,
893 WX(SIOCGIWRATE
) = ieee80211softmac_wx_get_rate
,
894 WX(SIOCSIWRTS
) = bcm43xx_wx_set_rts
,
895 WX(SIOCGIWRTS
) = bcm43xx_wx_get_rts
,
896 WX(SIOCSIWFRAG
) = bcm43xx_wx_set_frag
,
897 WX(SIOCGIWFRAG
) = bcm43xx_wx_get_frag
,
898 WX(SIOCSIWTXPOW
) = bcm43xx_wx_set_xmitpower
,
899 WX(SIOCGIWTXPOW
) = bcm43xx_wx_get_xmitpower
,
900 //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
901 //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
903 WX(SIOCSIWENCODE
) = bcm43xx_wx_set_encoding
,
904 WX(SIOCGIWENCODE
) = bcm43xx_wx_get_encoding
,
905 WX(SIOCSIWENCODEEXT
) = bcm43xx_wx_set_encodingext
,
906 WX(SIOCGIWENCODEEXT
) = bcm43xx_wx_get_encodingext
,
908 //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
909 //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
910 WX(SIOCSIWGENIE
) = ieee80211softmac_wx_set_genie
,
911 WX(SIOCGIWGENIE
) = ieee80211softmac_wx_get_genie
,
912 WX(SIOCSIWAUTH
) = ieee80211_wx_set_auth
,
913 WX(SIOCGIWAUTH
) = ieee80211_wx_get_auth
,
917 static const iw_handler bcm43xx_priv_wx_handlers
[] = {
918 /* Set Interference Mitigation Mode. */
919 bcm43xx_wx_set_interfmode
,
920 /* Get Interference Mitigation Mode. */
921 bcm43xx_wx_get_interfmode
,
922 /* Enable/Disable Short Preamble mode. */
923 bcm43xx_wx_set_shortpreamble
,
924 /* Get Short Preamble mode. */
925 bcm43xx_wx_get_shortpreamble
,
926 /* Enable/Disable Software Encryption mode */
927 bcm43xx_wx_set_swencryption
,
928 /* Get Software Encryption mode */
929 bcm43xx_wx_get_swencryption
,
930 /* Write SRPROM data. */
931 bcm43xx_wx_sprom_write
,
932 /* Read SPROM data. */
933 bcm43xx_wx_sprom_read
,
936 #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
937 #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
938 #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
939 #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
940 #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
941 #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
942 #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
943 #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
945 #define PRIV_WX_DUMMY(ioctl) \
951 static const struct iw_priv_args bcm43xx_priv_wx_args
[] = {
953 .cmd
= PRIV_WX_SET_INTERFMODE
,
954 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
955 .name
= "set_interfmode",
958 .cmd
= PRIV_WX_GET_INTERFMODE
,
959 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
960 .name
= "get_interfmode",
963 .cmd
= PRIV_WX_SET_SHORTPREAMBLE
,
964 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
965 .name
= "set_shortpreamb",
968 .cmd
= PRIV_WX_GET_SHORTPREAMBLE
,
969 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
970 .name
= "get_shortpreamb",
973 .cmd
= PRIV_WX_SET_SWENCRYPTION
,
974 .set_args
= IW_PRIV_TYPE_INT
| IW_PRIV_SIZE_FIXED
| 1,
975 .name
= "set_swencrypt",
978 .cmd
= PRIV_WX_GET_SWENCRYPTION
,
979 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| MAX_WX_STRING
,
980 .name
= "get_swencrypt",
983 .cmd
= PRIV_WX_SPROM_WRITE
,
984 .set_args
= IW_PRIV_TYPE_CHAR
| SPROM_BUFFERSIZE
,
985 .name
= "write_sprom",
988 .cmd
= PRIV_WX_SPROM_READ
,
989 .get_args
= IW_PRIV_TYPE_CHAR
| IW_PRIV_SIZE_FIXED
| SPROM_BUFFERSIZE
,
990 .name
= "read_sprom",
994 const struct iw_handler_def bcm43xx_wx_handlers_def
= {
995 .standard
= bcm43xx_wx_handlers
,
996 .num_standard
= ARRAY_SIZE(bcm43xx_wx_handlers
),
997 .num_private
= ARRAY_SIZE(bcm43xx_priv_wx_handlers
),
998 .num_private_args
= ARRAY_SIZE(bcm43xx_priv_wx_args
),
999 .private = bcm43xx_priv_wx_handlers
,
1000 .private_args
= bcm43xx_priv_wx_args
,
1001 .get_wireless_stats
= bcm43xx_get_wireless_stats
,