[PATCH] bcm43xx: reduce the size of bcm43xx_private by removing unneeded members.
[linux-2.6/linux-2.6-openrd.git] / drivers / net / wireless / bcm43xx / bcm43xx_wx.c
blob651ba60549571b8d0a1a80ab22821e08f6aaded9
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
52 static int bcm43xx_wx_get_name(struct net_device *net_dev,
53 struct iw_request_info *info,
54 union iwreq_data *data,
55 char *extra)
57 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
58 unsigned long flags;
59 int i;
60 struct bcm43xx_phyinfo *phy;
61 char suffix[7] = { 0 };
62 int have_a = 0, have_b = 0, have_g = 0;
64 bcm43xx_lock(bcm, flags);
65 for (i = 0; i < bcm->nr_80211_available; i++) {
66 phy = &(bcm->core_80211_ext[i].phy);
67 switch (phy->type) {
68 case BCM43xx_PHYTYPE_A:
69 have_a = 1;
70 break;
71 case BCM43xx_PHYTYPE_G:
72 have_g = 1;
73 case BCM43xx_PHYTYPE_B:
74 have_b = 1;
75 break;
76 default:
77 assert(0);
80 bcm43xx_unlock(bcm, flags);
82 i = 0;
83 if (have_a) {
84 suffix[i++] = 'a';
85 suffix[i++] = '/';
87 if (have_b) {
88 suffix[i++] = 'b';
89 suffix[i++] = '/';
91 if (have_g) {
92 suffix[i++] = 'g';
93 suffix[i++] = '/';
95 if (i != 0)
96 suffix[i - 1] = '\0';
98 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
100 return 0;
103 static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
104 struct iw_request_info *info,
105 union iwreq_data *data,
106 char *extra)
108 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
109 struct ieee80211softmac_device *softmac = bcm->softmac;
110 unsigned long flags;
111 u8 channel;
112 int freq;
113 int err = -EINVAL;
115 bcm43xx_lock_mmio(bcm, flags);
116 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
117 channel = data->freq.m;
118 freq = bcm43xx_channel_to_freq(bcm, channel);
119 } else {
120 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
121 freq = data->freq.m;
123 if (!bcm43xx_is_valid_channel(bcm, channel))
124 goto out_unlock;
125 if (bcm->initialized) {
126 //ieee80211softmac_disassoc(softmac, $REASON);
127 bcm43xx_mac_suspend(bcm);
128 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
129 bcm43xx_mac_enable(bcm);
130 } else {
131 bcm43xx_current_radio(bcm)->initial_channel = channel;
132 err = 0;
134 out_unlock:
135 bcm43xx_unlock_mmio(bcm, flags);
137 return err;
140 static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
141 struct iw_request_info *info,
142 union iwreq_data *data,
143 char *extra)
145 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
146 struct bcm43xx_radioinfo *radio;
147 unsigned long flags;
148 int err = -ENODEV;
149 u16 channel;
151 bcm43xx_lock(bcm, flags);
152 radio = bcm43xx_current_radio(bcm);
153 channel = radio->channel;
154 if (channel == 0xFF) {
155 assert(!bcm->initialized);
156 channel = radio->initial_channel;
157 if (channel == 0xFF)
158 goto out_unlock;
160 assert(channel > 0 && channel <= 1000);
161 data->freq.e = 1;
162 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
163 data->freq.flags = 1;
165 err = 0;
166 out_unlock:
167 bcm43xx_unlock(bcm, flags);
169 return err;
172 static int bcm43xx_wx_set_mode(struct net_device *net_dev,
173 struct iw_request_info *info,
174 union iwreq_data *data,
175 char *extra)
177 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
178 unsigned long flags;
179 int mode;
181 mode = data->mode;
182 if (mode == IW_MODE_AUTO)
183 mode = BCM43xx_INITIAL_IWMODE;
185 bcm43xx_lock_mmio(bcm, flags);
186 if (bcm->ieee->iw_mode != mode)
187 bcm43xx_set_iwmode(bcm, mode);
188 bcm43xx_unlock_mmio(bcm, flags);
190 return 0;
193 static int bcm43xx_wx_get_mode(struct net_device *net_dev,
194 struct iw_request_info *info,
195 union iwreq_data *data,
196 char *extra)
198 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
199 unsigned long flags;
201 bcm43xx_lock(bcm, flags);
202 data->mode = bcm->ieee->iw_mode;
203 bcm43xx_unlock(bcm, flags);
205 return 0;
208 static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev,
209 struct iw_request_info *info,
210 union iwreq_data *data,
211 char *extra)
213 /*TODO*/
214 return 0;
217 static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev,
218 struct iw_request_info *info,
219 union iwreq_data *data,
220 char *extra)
222 /*TODO*/
223 return 0;
226 static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
227 struct iw_request_info *info,
228 union iwreq_data *data,
229 char *extra)
231 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
232 struct iw_range *range = (struct iw_range *)extra;
233 const struct ieee80211_geo *geo;
234 unsigned long flags;
235 int i, j;
236 struct bcm43xx_phyinfo *phy;
238 data->data.length = sizeof(*range);
239 memset(range, 0, sizeof(*range));
241 //TODO: What about 802.11b?
242 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
243 range->throughput = 27 * 1000 * 1000;
245 range->max_qual.qual = 100;
246 /* TODO: Real max RSSI */
247 range->max_qual.level = 0;
248 range->max_qual.noise = 0;
249 range->max_qual.updated = 7;
251 range->avg_qual.qual = 70;
252 range->avg_qual.level = 0;
253 range->avg_qual.noise = 0;
254 range->avg_qual.updated = 7;
256 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
257 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
258 range->min_frag = MIN_FRAG_THRESHOLD;
259 range->max_frag = MAX_FRAG_THRESHOLD;
261 range->encoding_size[0] = 5;
262 range->encoding_size[1] = 13;
263 range->num_encoding_sizes = 2;
264 range->max_encoding_tokens = WEP_KEYS;
266 range->we_version_compiled = WIRELESS_EXT;
267 range->we_version_source = BCM43xx_WX_VERSION;
269 range->enc_capa = IW_ENC_CAPA_WPA |
270 IW_ENC_CAPA_WPA2 |
271 IW_ENC_CAPA_CIPHER_TKIP |
272 IW_ENC_CAPA_CIPHER_CCMP;
274 bcm43xx_lock(bcm, flags);
275 phy = bcm43xx_current_phy(bcm);
277 range->num_bitrates = 0;
278 i = 0;
279 if (phy->type == BCM43xx_PHYTYPE_A ||
280 phy->type == BCM43xx_PHYTYPE_G) {
281 range->num_bitrates = 8;
282 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
283 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
284 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
285 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
286 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
287 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
288 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
289 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
291 if (phy->type == BCM43xx_PHYTYPE_B ||
292 phy->type == BCM43xx_PHYTYPE_G) {
293 range->num_bitrates += 4;
294 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
295 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
296 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
297 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
300 geo = ieee80211_get_geo(bcm->ieee);
301 range->num_channels = geo->a_channels + geo->bg_channels;
302 j = 0;
303 for (i = 0; i < geo->a_channels; i++) {
304 if (j == IW_MAX_FREQUENCIES)
305 break;
306 range->freq[j].i = j + 1;
307 range->freq[j].m = geo->a[i].freq;//FIXME?
308 range->freq[j].e = 1;
309 j++;
311 for (i = 0; i < geo->bg_channels; i++) {
312 if (j == IW_MAX_FREQUENCIES)
313 break;
314 range->freq[j].i = j + 1;
315 range->freq[j].m = geo->bg[i].freq;//FIXME?
316 range->freq[j].e = 1;
317 j++;
319 range->num_frequency = j;
321 bcm43xx_unlock(bcm, flags);
323 return 0;
326 static int bcm43xx_wx_set_nick(struct net_device *net_dev,
327 struct iw_request_info *info,
328 union iwreq_data *data,
329 char *extra)
331 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
332 unsigned long flags;
333 size_t len;
335 bcm43xx_lock(bcm, flags);
336 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
337 memcpy(bcm->nick, extra, len);
338 bcm->nick[len] = '\0';
339 bcm43xx_unlock(bcm, flags);
341 return 0;
344 static int bcm43xx_wx_get_nick(struct net_device *net_dev,
345 struct iw_request_info *info,
346 union iwreq_data *data,
347 char *extra)
349 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
350 unsigned long flags;
351 size_t len;
353 bcm43xx_lock(bcm, flags);
354 len = strlen(bcm->nick) + 1;
355 memcpy(extra, bcm->nick, len);
356 data->data.length = (__u16)len;
357 data->data.flags = 1;
358 bcm43xx_unlock(bcm, flags);
360 return 0;
363 static int bcm43xx_wx_set_rts(struct net_device *net_dev,
364 struct iw_request_info *info,
365 union iwreq_data *data,
366 char *extra)
368 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
369 unsigned long flags;
370 int err = -EINVAL;
372 bcm43xx_lock(bcm, flags);
373 if (data->rts.disabled) {
374 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
375 err = 0;
376 } else {
377 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
378 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
379 bcm->rts_threshold = data->rts.value;
380 err = 0;
383 bcm43xx_unlock(bcm, flags);
385 return err;
388 static int bcm43xx_wx_get_rts(struct net_device *net_dev,
389 struct iw_request_info *info,
390 union iwreq_data *data,
391 char *extra)
393 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
394 unsigned long flags;
396 bcm43xx_lock(bcm, flags);
397 data->rts.value = bcm->rts_threshold;
398 data->rts.fixed = 0;
399 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
400 bcm43xx_unlock(bcm, flags);
402 return 0;
405 static int bcm43xx_wx_set_frag(struct net_device *net_dev,
406 struct iw_request_info *info,
407 union iwreq_data *data,
408 char *extra)
410 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
411 unsigned long flags;
412 int err = -EINVAL;
414 bcm43xx_lock(bcm, flags);
415 if (data->frag.disabled) {
416 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
417 err = 0;
418 } else {
419 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
420 data->frag.value <= MAX_FRAG_THRESHOLD) {
421 bcm->ieee->fts = data->frag.value & ~0x1;
422 err = 0;
425 bcm43xx_unlock(bcm, flags);
427 return err;
430 static int bcm43xx_wx_get_frag(struct net_device *net_dev,
431 struct iw_request_info *info,
432 union iwreq_data *data,
433 char *extra)
435 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
436 unsigned long flags;
438 bcm43xx_lock(bcm, flags);
439 data->frag.value = bcm->ieee->fts;
440 data->frag.fixed = 0;
441 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
442 bcm43xx_unlock(bcm, flags);
444 return 0;
447 static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
448 struct iw_request_info *info,
449 union iwreq_data *data,
450 char *extra)
452 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
453 struct bcm43xx_radioinfo *radio;
454 struct bcm43xx_phyinfo *phy;
455 unsigned long flags;
456 int err = -ENODEV;
457 u16 maxpower;
459 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
460 printk(PFX KERN_ERR "TX power not in dBm.\n");
461 return -EOPNOTSUPP;
464 bcm43xx_lock_mmio(bcm, flags);
465 if (!bcm->initialized)
466 goto out_unlock;
467 radio = bcm43xx_current_radio(bcm);
468 phy = bcm43xx_current_phy(bcm);
469 if (data->txpower.disabled != (!(radio->enabled))) {
470 if (data->txpower.disabled)
471 bcm43xx_radio_turn_off(bcm);
472 else
473 bcm43xx_radio_turn_on(bcm);
475 if (data->txpower.value > 0) {
476 /* desired and maxpower dBm values are in Q5.2 */
477 if (phy->type == BCM43xx_PHYTYPE_A)
478 maxpower = bcm->sprom.maxpower_aphy;
479 else
480 maxpower = bcm->sprom.maxpower_bgphy;
481 radio->txpower_desired = limit_value(data->txpower.value << 2,
482 0, maxpower);
483 bcm43xx_phy_xmitpower(bcm);
485 err = 0;
487 out_unlock:
488 bcm43xx_unlock_mmio(bcm, flags);
490 return err;
493 static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
494 struct iw_request_info *info,
495 union iwreq_data *data,
496 char *extra)
498 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
499 struct bcm43xx_radioinfo *radio;
500 unsigned long flags;
501 int err = -ENODEV;
503 bcm43xx_lock(bcm, flags);
504 if (!bcm->initialized)
505 goto out_unlock;
506 radio = bcm43xx_current_radio(bcm);
507 /* desired dBm value is in Q5.2 */
508 data->txpower.value = radio->txpower_desired >> 2;
509 data->txpower.fixed = 1;
510 data->txpower.flags = IW_TXPOW_DBM;
511 data->txpower.disabled = !(radio->enabled);
513 err = 0;
514 out_unlock:
515 bcm43xx_unlock(bcm, flags);
517 return err;
520 static int bcm43xx_wx_set_retry(struct net_device *net_dev,
521 struct iw_request_info *info,
522 union iwreq_data *data,
523 char *extra)
525 /*TODO*/
526 return 0;
529 static int bcm43xx_wx_get_retry(struct net_device *net_dev,
530 struct iw_request_info *info,
531 union iwreq_data *data,
532 char *extra)
534 /*TODO*/
535 return 0;
538 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
539 struct iw_request_info *info,
540 union iwreq_data *data,
541 char *extra)
543 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
544 int err;
546 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
548 return err;
551 static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
552 struct iw_request_info *info,
553 union iwreq_data *data,
554 char *extra)
556 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
557 int err;
559 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
561 return err;
564 static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
565 struct iw_request_info *info,
566 union iwreq_data *data,
567 char *extra)
569 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
570 int err;
572 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
574 return err;
577 static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
578 struct iw_request_info *info,
579 union iwreq_data *data,
580 char *extra)
582 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
583 int err;
585 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
587 return err;
590 static int bcm43xx_wx_set_power(struct net_device *net_dev,
591 struct iw_request_info *info,
592 union iwreq_data *data,
593 char *extra)
595 /*TODO*/
596 return 0;
599 static int bcm43xx_wx_get_power(struct net_device *net_dev,
600 struct iw_request_info *info,
601 union iwreq_data *data,
602 char *extra)
604 /*TODO*/
605 return 0;
608 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
609 struct iw_request_info *info,
610 union iwreq_data *data,
611 char *extra)
613 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
614 unsigned long flags;
615 int mode, err = 0;
617 mode = *((int *)extra);
618 switch (mode) {
619 case 0:
620 mode = BCM43xx_RADIO_INTERFMODE_NONE;
621 break;
622 case 1:
623 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
624 break;
625 case 2:
626 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
627 break;
628 case 3:
629 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
630 break;
631 default:
632 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
633 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
634 "3 => Auto-WLAN\n");
635 return -EINVAL;
638 bcm43xx_lock_mmio(bcm, flags);
639 if (bcm->initialized) {
640 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
641 if (err) {
642 printk(KERN_ERR PFX "Interference Mitigation not "
643 "supported by device\n");
645 } else {
646 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
647 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
648 "not supported while the interface is down.\n");
649 err = -ENODEV;
650 } else
651 bcm43xx_current_radio(bcm)->interfmode = mode;
653 bcm43xx_unlock_mmio(bcm, flags);
655 return err;
658 static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
659 struct iw_request_info *info,
660 union iwreq_data *data,
661 char *extra)
663 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
664 unsigned long flags;
665 int mode;
667 bcm43xx_lock(bcm, flags);
668 mode = bcm43xx_current_radio(bcm)->interfmode;
669 bcm43xx_unlock(bcm, flags);
671 switch (mode) {
672 case BCM43xx_RADIO_INTERFMODE_NONE:
673 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
674 break;
675 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
676 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
677 break;
678 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
679 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
680 break;
681 default:
682 assert(0);
684 data->data.length = strlen(extra) + 1;
686 return 0;
689 static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
690 struct iw_request_info *info,
691 union iwreq_data *data,
692 char *extra)
694 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
695 unsigned long flags;
696 int on;
698 on = *((int *)extra);
699 bcm43xx_lock(bcm, flags);
700 bcm->short_preamble = !!on;
701 bcm43xx_unlock(bcm, flags);
703 return 0;
706 static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
707 struct iw_request_info *info,
708 union iwreq_data *data,
709 char *extra)
711 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
712 unsigned long flags;
713 int on;
715 bcm43xx_lock(bcm, flags);
716 on = bcm->short_preamble;
717 bcm43xx_unlock(bcm, flags);
719 if (on)
720 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
721 else
722 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
723 data->data.length = strlen(extra) + 1;
725 return 0;
728 static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
729 struct iw_request_info *info,
730 union iwreq_data *data,
731 char *extra)
733 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
734 unsigned long flags;
735 int on;
737 on = *((int *)extra);
739 bcm43xx_lock(bcm, flags);
740 bcm->ieee->host_encrypt = !!on;
741 bcm->ieee->host_decrypt = !!on;
742 bcm->ieee->host_build_iv = !on;
743 bcm43xx_unlock(bcm, flags);
745 return 0;
748 static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
749 struct iw_request_info *info,
750 union iwreq_data *data,
751 char *extra)
753 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
754 unsigned long flags;
755 int on;
757 bcm43xx_lock(bcm, flags);
758 on = bcm->ieee->host_encrypt;
759 bcm43xx_unlock(bcm, flags);
761 if (on)
762 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
763 else
764 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
765 data->data.length = strlen(extra + 1);
767 return 0;
770 /* Enough buffer to hold a hexdump of the sprom data. */
771 #define SPROM_BUFFERSIZE 512
773 static int sprom2hex(const u16 *sprom, char *dump)
775 int i, pos = 0;
777 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
778 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
779 "%04X", swab16(sprom[i]) & 0xFFFF);
782 return pos + 1;
785 static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
787 char tmp[5] = { 0 };
788 int cnt = 0;
789 unsigned long parsed;
791 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
792 return -EINVAL;
793 while (cnt < BCM43xx_SPROM_SIZE) {
794 memcpy(tmp, dump, 4);
795 dump += 4;
796 parsed = simple_strtoul(tmp, NULL, 16);
797 sprom[cnt++] = swab16((u16)parsed);
800 return 0;
803 static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
804 struct iw_request_info *info,
805 union iwreq_data *data,
806 char *extra)
808 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
809 int err = -EPERM;
810 u16 *sprom;
811 unsigned long flags;
813 if (!capable(CAP_SYS_RAWIO))
814 goto out;
816 err = -ENOMEM;
817 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
818 GFP_KERNEL);
819 if (!sprom)
820 goto out;
822 bcm43xx_lock_mmio(bcm, flags);
823 err = -ENODEV;
824 if (bcm->initialized)
825 err = bcm43xx_sprom_read(bcm, sprom);
826 bcm43xx_unlock_mmio(bcm, flags);
827 if (!err)
828 data->data.length = sprom2hex(sprom, extra);
829 kfree(sprom);
830 out:
831 return err;
834 static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
835 struct iw_request_info *info,
836 union iwreq_data *data,
837 char *extra)
839 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
840 int err = -EPERM;
841 u16 *sprom;
842 unsigned long flags;
843 char *input;
844 unsigned int len;
846 if (!capable(CAP_SYS_RAWIO))
847 goto out;
849 err = -ENOMEM;
850 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
851 GFP_KERNEL);
852 if (!sprom)
853 goto out;
855 len = data->data.length;
856 extra[len - 1] = '\0';
857 input = strchr(extra, ':');
858 if (input) {
859 input++;
860 len -= input - extra;
861 } else
862 input = extra;
863 err = hex2sprom(sprom, input, len);
864 if (err)
865 goto out_kfree;
867 bcm43xx_lock_mmio(bcm, flags);
868 err = -ENODEV;
869 if (bcm->initialized)
870 err = bcm43xx_sprom_write(bcm, sprom);
871 bcm43xx_unlock_mmio(bcm, flags);
872 out_kfree:
873 kfree(sprom);
874 out:
875 return err;
879 #ifdef WX
880 # undef WX
881 #endif
882 #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
883 static const iw_handler bcm43xx_wx_handlers[] = {
884 /* Wireless Identification */
885 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
886 /* Basic operations */
887 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
888 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
889 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
890 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
891 /* Informative stuff */
892 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
893 /* Access Point manipulation */
894 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
895 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
896 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
897 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
898 /* 802.11 specific support */
899 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
900 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
901 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
902 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
903 /* Other parameters */
904 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
905 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
906 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
907 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
908 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
909 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
910 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
911 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
912 //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
913 //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
914 /* Encoding */
915 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
916 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
917 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
918 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
919 /* Power saving */
920 //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
921 //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
922 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
923 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
924 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
925 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
927 #undef WX
929 static const iw_handler bcm43xx_priv_wx_handlers[] = {
930 /* Set Interference Mitigation Mode. */
931 bcm43xx_wx_set_interfmode,
932 /* Get Interference Mitigation Mode. */
933 bcm43xx_wx_get_interfmode,
934 /* Enable/Disable Short Preamble mode. */
935 bcm43xx_wx_set_shortpreamble,
936 /* Get Short Preamble mode. */
937 bcm43xx_wx_get_shortpreamble,
938 /* Enable/Disable Software Encryption mode */
939 bcm43xx_wx_set_swencryption,
940 /* Get Software Encryption mode */
941 bcm43xx_wx_get_swencryption,
942 /* Write SRPROM data. */
943 bcm43xx_wx_sprom_write,
944 /* Read SPROM data. */
945 bcm43xx_wx_sprom_read,
948 #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
949 #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
950 #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
951 #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
952 #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
953 #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
954 #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
955 #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
957 #define PRIV_WX_DUMMY(ioctl) \
959 .cmd = (ioctl), \
960 .name = "__unused" \
963 static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
965 .cmd = PRIV_WX_SET_INTERFMODE,
966 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
967 .name = "set_interfmode",
970 .cmd = PRIV_WX_GET_INTERFMODE,
971 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
972 .name = "get_interfmode",
975 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
976 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
977 .name = "set_shortpreambl",
980 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
981 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
982 .name = "get_shortpreambl",
985 .cmd = PRIV_WX_SET_SWENCRYPTION,
986 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
987 .name = "set_swencryption",
990 .cmd = PRIV_WX_GET_SWENCRYPTION,
991 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
992 .name = "get_swencryption",
995 .cmd = PRIV_WX_SPROM_WRITE,
996 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
997 .name = "write_sprom",
1000 .cmd = PRIV_WX_SPROM_READ,
1001 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1002 .name = "read_sprom",
1006 const struct iw_handler_def bcm43xx_wx_handlers_def = {
1007 .standard = bcm43xx_wx_handlers,
1008 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
1009 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1010 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
1011 .private = bcm43xx_priv_wx_handlers,
1012 .private_args = bcm43xx_priv_wx_args,
1015 /* vim: set ts=8 sw=8 sts=8: */