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