]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/net/wireless/bcm43xx/bcm43xx_wx.c
[PATCH] bcm43xx: Wireless Ext update
[net-next-2.6.git] / drivers / net / wireless / bcm43xx / bcm43xx_wx.c
CommitLineData
f222313a
JL
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27 Boston, MA 02110-1301, USA.
28
29*/
30
31#include <linux/wireless.h>
32#include <net/iw_handler.h>
33#include <net/ieee80211softmac.h>
34#include <net/ieee80211softmac_wx.h>
35#include <linux/capability.h>
36#include <linux/sched.h> /* for capable() */
37#include <linux/delay.h>
38
39#include "bcm43xx.h"
40#include "bcm43xx_wx.h"
41#include "bcm43xx_main.h"
42#include "bcm43xx_radio.h"
43
8fa252d0
MB
44
45/* The WIRELESS_EXT version, which is implemented by this driver. */
46#define BCM43xx_WX_VERSION 18
47
48
f222313a
JL
49/* Define to enable a printk on each wx handler function invocation */
50//#define BCM43xx_WX_DEBUG
51
52
53#ifdef BCM43xx_WX_DEBUG
54# define printk_wx printk
55#else
56# define printk_wx(x...) do { /* nothing */ } while (0)
57#endif
58#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__);
59
60#define MAX_WX_STRING 80
61
62
63static int bcm43xx_wx_get_name(struct net_device *net_dev,
64 struct iw_request_info *info,
65 union iwreq_data *data,
66 char *extra)
67{
68 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
69 unsigned long flags;
70 int i, nr_80211;
71 struct bcm43xx_phyinfo *phy;
72 char suffix[7] = { 0 };
73 int have_a = 0, have_b = 0, have_g = 0;
74
75 wx_enter();
76
77 spin_lock_irqsave(&bcm->lock, flags);
78 nr_80211 = bcm43xx_num_80211_cores(bcm);
79 for (i = 0; i < nr_80211; i++) {
80 phy = bcm->phy + i;
81 switch (phy->type) {
82 case BCM43xx_PHYTYPE_A:
83 have_a = 1;
84 break;
85 case BCM43xx_PHYTYPE_G:
86 have_g = 1;
87 case BCM43xx_PHYTYPE_B:
88 have_b = 1;
89 break;
90 default:
91 assert(0);
92 }
93 }
94 spin_unlock_irqrestore(&bcm->lock, flags);
95
96 i = 0;
97 if (have_a) {
98 suffix[i++] = 'a';
99 suffix[i++] = '/';
100 }
101 if (have_b) {
102 suffix[i++] = 'b';
103 suffix[i++] = '/';
104 }
105 if (have_g) {
106 suffix[i++] = 'g';
107 suffix[i++] = '/';
108 }
109 if (i != 0)
110 suffix[i - 1] = '\0';
111
112 snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
113
114 return 0;
115}
116
117static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
118 struct iw_request_info *info,
119 union iwreq_data *data,
120 char *extra)
121{
122 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
123 struct ieee80211softmac_device *softmac = bcm->softmac;
124 unsigned long flags;
125 u8 channel;
126 int freq;
127 int err = 0;
128
129 wx_enter();
130
131 if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
132 channel = data->freq.m;
133 freq = bcm43xx_channel_to_freq(bcm, channel);
134 } else {
135 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
136 freq = data->freq.m;
137 }
138 if (!bcm43xx_is_valid_channel(bcm, channel))
139 return -EINVAL;
140
141 spin_lock_irqsave(&bcm->lock, flags);
142 if (bcm->initialized) {
143 //ieee80211softmac_disassoc(softmac, $REASON);
144 bcm43xx_mac_suspend(bcm);
145 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
146 bcm43xx_mac_enable(bcm);
147 } else
148 bcm->current_core->radio->initial_channel = channel;
149 spin_unlock_irqrestore(&bcm->lock, flags);
150 if (!err)
151 printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel);
152
153 return err;
154}
155
156static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
157 struct iw_request_info *info,
158 union iwreq_data *data,
159 char *extra)
160{
161 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
162 unsigned long flags;
163 int err = -ENODEV;
164 u16 channel;
165
166 wx_enter();
167
168 spin_lock_irqsave(&bcm->lock, flags);
169 channel = bcm->current_core->radio->channel;
170 if (channel == 0xFF) {
171 assert(!bcm->initialized);
172 channel = bcm->current_core->radio->initial_channel;
173 if (channel == 0xFF)
174 goto out_unlock;
175 }
176 assert(channel > 0 && channel <= 1000);
177 data->freq.e = 1;
178 data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
179 data->freq.flags = 1;
180
181 err = 0;
182out_unlock:
183 spin_unlock_irqrestore(&bcm->lock, flags);
184
185 return err;
186}
187
188static int bcm43xx_wx_set_mode(struct net_device *net_dev,
189 struct iw_request_info *info,
190 union iwreq_data *data,
191 char *extra)
192{
193 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
194 unsigned long flags;
195 int mode;
196
197 wx_enter();
198
199 mode = data->mode;
200 if (mode == IW_MODE_AUTO)
201 mode = BCM43xx_INITIAL_IWMODE;
202
203 spin_lock_irqsave(&bcm->lock, flags);
204 if (bcm->ieee->iw_mode != mode)
205 bcm43xx_set_iwmode(bcm, mode);
206 spin_unlock_irqrestore(&bcm->lock, flags);
207
208 return 0;
209}
210
211static int bcm43xx_wx_get_mode(struct net_device *net_dev,
212 struct iw_request_info *info,
213 union iwreq_data *data,
214 char *extra)
215{
216 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
217 unsigned long flags;
218
219 wx_enter();
220
221 spin_lock_irqsave(&bcm->lock, flags);
222 data->mode = bcm->ieee->iw_mode;
223 spin_unlock_irqrestore(&bcm->lock, flags);
224
225 return 0;
226}
227
228static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev,
229 struct iw_request_info *info,
230 union iwreq_data *data,
231 char *extra)
232{
233 wx_enter();
234 /*TODO*/
235 return 0;
236}
237
238static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev,
239 struct iw_request_info *info,
240 union iwreq_data *data,
241 char *extra)
242{
243 wx_enter();
244 /*TODO*/
245 return 0;
246}
247
248static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
249 struct iw_request_info *info,
250 union iwreq_data *data,
251 char *extra)
252{
253 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
254 struct iw_range *range = (struct iw_range *)extra;
255 const struct ieee80211_geo *geo;
256 unsigned long flags;
257 int i, j;
258
259 wx_enter();
260
261 data->data.length = sizeof(*range);
262 memset(range, 0, sizeof(*range));
263
264 //TODO: What about 802.11b?
265 /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
266 range->throughput = 27 * 1000 * 1000;
267
268 range->max_qual.qual = 100;
269 /* TODO: Real max RSSI */
270 range->max_qual.level = 0;
271 range->max_qual.noise = 0;
272 range->max_qual.updated = 7;
273
274 range->avg_qual.qual = 70;
275 range->avg_qual.level = 0;
276 range->avg_qual.noise = 0;
277 range->avg_qual.updated = 7;
278
279 range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
280 range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
281 range->min_frag = MIN_FRAG_THRESHOLD;
282 range->max_frag = MAX_FRAG_THRESHOLD;
283
284 range->encoding_size[0] = 5;
285 range->encoding_size[1] = 13;
286 range->num_encoding_sizes = 2;
287 range->max_encoding_tokens = WEP_KEYS;
288
289 range->we_version_compiled = WIRELESS_EXT;
8fa252d0
MB
290 range->we_version_source = BCM43xx_WX_VERSION;
291
292 range->enc_capa = IW_ENC_CAPA_WPA |
293 IW_ENC_CAPA_WPA2 |
294 IW_ENC_CAPA_CIPHER_TKIP |
295 IW_ENC_CAPA_CIPHER_CCMP;
f222313a
JL
296
297 spin_lock_irqsave(&bcm->lock, flags);
298
299 range->num_bitrates = 0;
300 i = 0;
301 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ||
302 bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
303 range->num_bitrates = 8;
304 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
305 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
306 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
307 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
308 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
309 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
310 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
311 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
312 }
313 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B ||
314 bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) {
315 range->num_bitrates += 4;
316 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
317 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
318 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
319 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
320 }
321
322 geo = ieee80211_get_geo(bcm->ieee);
323 range->num_channels = geo->a_channels + geo->bg_channels;
324 j = 0;
325 for (i = 0; i < geo->a_channels; i++) {
326 if (j == IW_MAX_FREQUENCIES)
327 break;
328 range->freq[j].i = j + 1;
329 range->freq[j].m = geo->a[i].freq;//FIXME?
330 range->freq[j].e = 1;
331 j++;
332 }
333 for (i = 0; i < geo->bg_channels; i++) {
334 if (j == IW_MAX_FREQUENCIES)
335 break;
336 range->freq[j].i = j + 1;
337 range->freq[j].m = geo->bg[i].freq;//FIXME?
338 range->freq[j].e = 1;
339 j++;
340 }
341 range->num_frequency = j;
342
343 spin_unlock_irqrestore(&bcm->lock, flags);
344
345 return 0;
346}
347
348static int bcm43xx_wx_set_nick(struct net_device *net_dev,
349 struct iw_request_info *info,
350 union iwreq_data *data,
351 char *extra)
352{
353 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
354 unsigned long flags;
355 size_t len;
356
357 wx_enter();
358
359 spin_lock_irqsave(&bcm->lock, flags);
360 len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
361 memcpy(bcm->nick, extra, len);
362 bcm->nick[len] = '\0';
363 spin_unlock_irqrestore(&bcm->lock, flags);
364
365 return 0;
366}
367
368static int bcm43xx_wx_get_nick(struct net_device *net_dev,
369 struct iw_request_info *info,
370 union iwreq_data *data,
371 char *extra)
372{
373 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
374 unsigned long flags;
375 size_t len;
376
377 wx_enter();
378
379 spin_lock_irqsave(&bcm->lock, flags);
380 len = strlen(bcm->nick) + 1;
381 memcpy(extra, bcm->nick, len);
382 data->data.length = (__u16)len;
383 data->data.flags = 1;
384 spin_unlock_irqrestore(&bcm->lock, flags);
385
386 return 0;
387}
388
389static int bcm43xx_wx_set_rts(struct net_device *net_dev,
390 struct iw_request_info *info,
391 union iwreq_data *data,
392 char *extra)
393{
394 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
395 unsigned long flags;
396 int err = -EINVAL;
397
398 wx_enter();
399
400 spin_lock_irqsave(&bcm->lock, flags);
401 if (data->rts.disabled) {
402 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
403 err = 0;
404 } else {
405 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
406 data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
407 bcm->rts_threshold = data->rts.value;
408 err = 0;
409 }
410 }
411 spin_unlock_irqrestore(&bcm->lock, flags);
412
413 return err;
414}
415
416static int bcm43xx_wx_get_rts(struct net_device *net_dev,
417 struct iw_request_info *info,
418 union iwreq_data *data,
419 char *extra)
420{
421 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
422 unsigned long flags;
423
424 wx_enter();
425
426 spin_lock_irqsave(&bcm->lock, flags);
427 data->rts.value = bcm->rts_threshold;
428 data->rts.fixed = 0;
429 data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
430 spin_unlock_irqrestore(&bcm->lock, flags);
431
432 return 0;
433}
434
435static int bcm43xx_wx_set_frag(struct net_device *net_dev,
436 struct iw_request_info *info,
437 union iwreq_data *data,
438 char *extra)
439{
440 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
441 unsigned long flags;
442 int err = -EINVAL;
443
444 wx_enter();
445
446 spin_lock_irqsave(&bcm->lock, flags);
447 if (data->frag.disabled) {
448 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
449 err = 0;
450 } else {
451 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
452 data->frag.value <= MAX_FRAG_THRESHOLD) {
453 bcm->ieee->fts = data->frag.value & ~0x1;
454 err = 0;
455 }
456 }
457 spin_unlock_irqrestore(&bcm->lock, flags);
458
459 return err;
460}
461
462static int bcm43xx_wx_get_frag(struct net_device *net_dev,
463 struct iw_request_info *info,
464 union iwreq_data *data,
465 char *extra)
466{
467 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
468 unsigned long flags;
469
470 wx_enter();
471
472 spin_lock_irqsave(&bcm->lock, flags);
473 data->frag.value = bcm->ieee->fts;
474 data->frag.fixed = 0;
475 data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
476 spin_unlock_irqrestore(&bcm->lock, flags);
477
478 return 0;
479}
480
481static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
482 struct iw_request_info *info,
483 union iwreq_data *data,
484 char *extra)
485{
486 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
487 unsigned long flags;
488 int err = -ENODEV;
489
490 wx_enter();
491
492 spin_lock_irqsave(&bcm->lock, flags);
493 if (!bcm->initialized)
494 goto out_unlock;
495 if (data->power.disabled != (!(bcm->current_core->radio->enabled))) {
496 if (data->power.disabled)
497 bcm43xx_radio_turn_off(bcm);
498 else
499 bcm43xx_radio_turn_on(bcm);
500 }
501 //TODO: set txpower.
502 err = 0;
503
504out_unlock:
505 spin_unlock_irqrestore(&bcm->lock, flags);
506
507 return err;
508}
509
510static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
511 struct iw_request_info *info,
512 union iwreq_data *data,
513 char *extra)
514{
515 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
516 unsigned long flags;
517
518 wx_enter();
519
520 spin_lock_irqsave(&bcm->lock, flags);
521//TODO data->power.value = ???
522 data->power.fixed = 1;
523 data->power.flags = IW_TXPOW_DBM;
524 data->power.disabled = !(bcm->current_core->radio->enabled);
525 spin_unlock_irqrestore(&bcm->lock, flags);
526
527 return 0;
528}
529
530static int bcm43xx_wx_set_retry(struct net_device *net_dev,
531 struct iw_request_info *info,
532 union iwreq_data *data,
533 char *extra)
534{
535 wx_enter();
536 /*TODO*/
537 return 0;
538}
539
540static int bcm43xx_wx_get_retry(struct net_device *net_dev,
541 struct iw_request_info *info,
542 union iwreq_data *data,
543 char *extra)
544{
545 wx_enter();
546 /*TODO*/
547 return 0;
548}
549
550static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
551 struct iw_request_info *info,
552 union iwreq_data *data,
553 char *extra)
554{
555 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
556 int err;
557
558 wx_enter();
559
560 err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
561
562 return err;
563}
564
565static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
566 struct iw_request_info *info,
567 union iwreq_data *data,
568 char *extra)
569{
570 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
571 int err;
572
573 wx_enter();
574
575 err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
576
577 return err;
578}
579
580static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
581 struct iw_request_info *info,
582 union iwreq_data *data,
583 char *extra)
584{
585 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
586 int err;
587
588 wx_enter();
589
590 err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
591
592 return err;
593}
594
595static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
596 struct iw_request_info *info,
597 union iwreq_data *data,
598 char *extra)
599{
600 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
601 int err;
602
603 wx_enter();
604
605 err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
606
607 return err;
608}
609
610static int bcm43xx_wx_set_power(struct net_device *net_dev,
611 struct iw_request_info *info,
612 union iwreq_data *data,
613 char *extra)
614{
615 wx_enter();
616 /*TODO*/
617 return 0;
618}
619
620static int bcm43xx_wx_get_power(struct net_device *net_dev,
621 struct iw_request_info *info,
622 union iwreq_data *data,
623 char *extra)
624{
625 wx_enter();
626 /*TODO*/
627 return 0;
628}
629
630static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
631 struct iw_request_info *info,
632 union iwreq_data *data,
633 char *extra)
634{
635 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
636 unsigned long flags;
637 int mode, err = 0;
638
639 wx_enter();
640
641 mode = *((int *)extra);
642 switch (mode) {
643 case 0:
644 mode = BCM43xx_RADIO_INTERFMODE_NONE;
645 break;
646 case 1:
647 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
648 break;
649 case 2:
650 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
651 break;
652 case 3:
653 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
654 break;
655 default:
656 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
657 "0 => None, 1 => Non-WLAN, 2 => WLAN, "
658 "3 => Auto-WLAN\n");
659 return -EINVAL;
660 }
661
662 spin_lock_irqsave(&bcm->lock, flags);
663 if (bcm->initialized) {
664 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
665 if (err) {
666 printk(KERN_ERR PFX "Interference Mitigation not "
667 "supported by device\n");
668 }
669 } else {
670 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
671 printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
672 "not supported while the interface is down.\n");
673 err = -ENODEV;
674 } else
675 bcm->current_core->radio->interfmode = mode;
676 }
677 spin_unlock_irqrestore(&bcm->lock, flags);
678
679 return err;
680}
681
682static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
683 struct iw_request_info *info,
684 union iwreq_data *data,
685 char *extra)
686{
687 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
688 unsigned long flags;
689 int mode;
690
691 wx_enter();
692
693 spin_lock_irqsave(&bcm->lock, flags);
694 mode = bcm->current_core->radio->interfmode;
695 spin_unlock_irqrestore(&bcm->lock, flags);
696
697 switch (mode) {
698 case BCM43xx_RADIO_INTERFMODE_NONE:
699 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
700 break;
701 case BCM43xx_RADIO_INTERFMODE_NONWLAN:
702 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
703 break;
704 case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
705 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
706 break;
707 default:
708 assert(0);
709 }
710 data->data.length = strlen(extra) + 1;
711
712 return 0;
713}
714
715static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
716 struct iw_request_info *info,
717 union iwreq_data *data,
718 char *extra)
719{
720 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
721 unsigned long flags;
722 int on;
723
724 wx_enter();
725
726 on = *((int *)extra);
727 spin_lock_irqsave(&bcm->lock, flags);
728 bcm->short_preamble = !!on;
729 spin_unlock_irqrestore(&bcm->lock, flags);
730
731 return 0;
732}
733
734static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
735 struct iw_request_info *info,
736 union iwreq_data *data,
737 char *extra)
738{
739 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
740 unsigned long flags;
741 int on;
742
743 wx_enter();
744
745 spin_lock_irqsave(&bcm->lock, flags);
746 on = bcm->short_preamble;
747 spin_unlock_irqrestore(&bcm->lock, flags);
748
749 if (on)
750 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
751 else
752 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
753 data->data.length = strlen(extra) + 1;
754
755 return 0;
756}
757
758static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
759 struct iw_request_info *info,
760 union iwreq_data *data,
761 char *extra)
762{
763 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
764 unsigned long flags;
765 int on;
766
767 wx_enter();
768
769 on = *((int *)extra);
770 spin_lock_irqsave(&bcm->lock, flags);
771 bcm->ieee->host_encrypt = !!on;
772 bcm->ieee->host_decrypt = !!on;
773 bcm->ieee->host_build_iv = !on;
774
775 spin_unlock_irqrestore(&bcm->lock, flags);
776
777 return 0;
778}
779
780static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
781 struct iw_request_info *info,
782 union iwreq_data *data,
783 char *extra)
784{
785 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
786 unsigned long flags;
787 int on;
788
789 wx_enter();
790
791 spin_lock_irqsave(&bcm->lock, flags);
792 on = bcm->ieee->host_encrypt;
793 spin_unlock_irqrestore(&bcm->lock, flags);
794
795 if (on)
796 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
797 else
798 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
799 data->data.length = strlen(extra + 1);
800
801 return 0;
802}
803
804/* Enough buffer to hold a hexdump of the sprom data. */
805#define SPROM_BUFFERSIZE 512
806
807static int sprom2hex(const u16 *sprom, char *dump)
808{
809 int i, pos = 0;
810
811 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
812 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
813 "%04X", swab16(sprom[i]) & 0xFFFF);
814 }
815
816 return pos + 1;
817}
818
819static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
820{
821 char tmp[5] = { 0 };
822 int cnt = 0;
823 unsigned long parsed;
824 u8 crc, expected_crc;
825
826 if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
827 return -EINVAL;
828 while (cnt < BCM43xx_SPROM_SIZE) {
829 memcpy(tmp, dump, 4);
830 dump += 4;
831 parsed = simple_strtoul(tmp, NULL, 16);
832 sprom[cnt++] = swab16((u16)parsed);
833 }
834
835 crc = bcm43xx_sprom_crc(sprom);
836 expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
837 if (crc != expected_crc) {
838 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
839 return -EINVAL;
840 }
841
842 return 0;
843}
844
845static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
846 struct iw_request_info *info,
847 union iwreq_data *data,
848 char *extra)
849{
850 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
851 int err = -EPERM, i;
852 u16 *sprom;
853 unsigned long flags;
854
855 if (!capable(CAP_SYS_RAWIO))
856 goto out;
857
858 err = -ENOMEM;
859 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
860 GFP_KERNEL);
861 if (!sprom)
862 goto out;
863
864 spin_lock_irqsave(&bcm->lock, flags);
865 err = -ENODEV;
866 if (!bcm->initialized) {
867 spin_unlock_irqrestore(&bcm->lock, flags);
868 goto out_kfree;
869 }
870 for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
871 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
872 spin_unlock_irqrestore(&bcm->lock, flags);
873
874 data->data.length = sprom2hex(sprom, extra);
875
876 err = 0;
877out_kfree:
878 kfree(sprom);
879out:
880 return err;
881}
882
883static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
884 struct iw_request_info *info,
885 union iwreq_data *data,
886 char *extra)
887{
888 struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
889 int err = -EPERM;
890 u16 *sprom;
891 unsigned long flags;
892 char *input;
893 unsigned int len;
894 u32 spromctl;
895 int i;
896
897 if (!capable(CAP_SYS_RAWIO))
898 goto out;
899
900 err = -ENOMEM;
901 sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
902 GFP_KERNEL);
903 if (!sprom)
904 goto out;
905
906 len = data->data.length;
907 extra[len - 1] = '\0';
908 input = strchr(extra, ':');
909 if (input) {
910 input++;
911 len -= input - extra;
912 } else
913 input = extra;
914 err = hex2sprom(sprom, input, len);
915 if (err)
916 goto out_kfree;
917
918 spin_lock_irqsave(&bcm->lock, flags);
919 err = -ENODEV;
920 if (!bcm->initialized) {
921 spin_unlock_irqrestore(&bcm->lock, flags);
922 goto out_kfree;
923 }
924
925 printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
926 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
927 if (err) {
928 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
929 goto out_unlock;
930 }
931 spromctl |= 0x10; /* SPROM WRITE enable. */
932 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
933 if (err) {
934 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
935 goto out_unlock;
936 }
937 /* We must burn lots of CPU cycles here, but that does not
938 * really matter as one does not write the SPROM every other minute...
939 */
940 printk(KERN_INFO PFX "[ 0%%");
941 mdelay(500);
942 for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
943 if (i == 16)
944 printk("25%%");
945 else if (i == 32)
946 printk("50%%");
947 else if (i == 48)
948 printk("75%%");
949 else if (i % 2)
950 printk(".");
951//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
952 mdelay(20);
953 }
954 spromctl &= ~0x10; /* SPROM WRITE enable. */
955 bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
956 if (err) {
957 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
958 goto out_unlock;
959 }
960 mdelay(500);
961 printk("100%% ]\n");
962 printk(KERN_INFO PFX "SPROM written.\n");
963 err = 0;
964out_unlock:
965 spin_unlock_irqrestore(&bcm->lock, flags);
966out_kfree:
967 kfree(sprom);
968out:
969 return err;
970}
971
972
973#ifdef WX
974# undef WX
975#endif
976#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
977static const iw_handler bcm43xx_wx_handlers[] = {
978 /* Wireless Identification */
979 WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
980 /* Basic operations */
981 WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
982 WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
983 WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
984 WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
985 /* Informative stuff */
986 WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
987 /* Access Point manipulation */
988 WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
989 WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
990 WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
991 WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
992 /* 802.11 specific support */
993 WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
994 WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
995 WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
996 WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
997 /* Other parameters */
998 WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
999 WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
1000 WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
1001 WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
1002 WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
1003 WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
1004 WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
1005 WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
1006//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
1007//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
1008 /* Encoding */
1009 WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
1010 WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
1011 WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
1012 WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
1013 /* Power saving */
1014//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
1015//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
1016 WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
1017 WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
1018 WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
1019 WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
1020};
1021#undef WX
1022
1023static const iw_handler bcm43xx_priv_wx_handlers[] = {
1024 /* Set Interference Mitigation Mode. */
1025 bcm43xx_wx_set_interfmode,
1026 /* Get Interference Mitigation Mode. */
1027 bcm43xx_wx_get_interfmode,
1028 /* Enable/Disable Short Preamble mode. */
1029 bcm43xx_wx_set_shortpreamble,
1030 /* Get Short Preamble mode. */
1031 bcm43xx_wx_get_shortpreamble,
1032 /* Enable/Disable Software Encryption mode */
1033 bcm43xx_wx_set_swencryption,
1034 /* Get Software Encryption mode */
1035 bcm43xx_wx_get_swencryption,
1036 /* Write SRPROM data. */
1037 bcm43xx_wx_sprom_write,
1038 /* Read SPROM data. */
1039 bcm43xx_wx_sprom_read,
1040};
1041
1042#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
1043#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
1044#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
1045#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
1046#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
1047#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
1048#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
1049#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
1050
1051#define PRIV_WX_DUMMY(ioctl) \
1052 { \
1053 .cmd = (ioctl), \
1054 .name = "__unused" \
1055 }
1056
1057static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
1058 {
1059 .cmd = PRIV_WX_SET_INTERFMODE,
1060 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1061 .name = "set_interfmode",
1062 },
1063 {
1064 .cmd = PRIV_WX_GET_INTERFMODE,
1065 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1066 .name = "get_interfmode",
1067 },
1068 {
1069 .cmd = PRIV_WX_SET_SHORTPREAMBLE,
1070 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1071 .name = "set_shortpreambl",
1072 },
1073 {
1074 .cmd = PRIV_WX_GET_SHORTPREAMBLE,
1075 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1076 .name = "get_shortpreambl",
1077 },
1078 {
1079 .cmd = PRIV_WX_SET_SWENCRYPTION,
1080 .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1081 .name = "set_swencryption",
1082 },
1083 {
1084 .cmd = PRIV_WX_GET_SWENCRYPTION,
1085 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1086 .name = "get_swencryption",
1087 },
1088 {
1089 .cmd = PRIV_WX_SPROM_WRITE,
1090 .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
1091 .name = "write_sprom",
1092 },
1093 {
1094 .cmd = PRIV_WX_SPROM_READ,
1095 .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1096 .name = "read_sprom",
1097 },
1098};
1099
1100const struct iw_handler_def bcm43xx_wx_handlers_def = {
1101 .standard = bcm43xx_wx_handlers,
1102 .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
1103 .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1104 .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
1105 .private = bcm43xx_priv_wx_handlers,
1106 .private_args = bcm43xx_priv_wx_args,
1107};
1108
1109/* vim: set ts=8 sw=8 sts=8: */