[PATCH] bcm43xx: fix txpower reporting in WE.
[linux-2.6] / 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
44
45 /* The WIRELESS_EXT version, which is implemented by this driver. */
46 #define BCM43xx_WX_VERSION      18
47
48
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
63 static 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
117 static 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
156 static 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;
182 out_unlock:
183         spin_unlock_irqrestore(&bcm->lock, flags);
184
185         return err;
186 }
187
188 static 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
211 static 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
228 static 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
238 static 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
248 static 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;
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;
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
348 static 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
368 static 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
389 static 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
416 static 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
435 static 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
462 static 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
481 static 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         struct bcm43xx_radioinfo *radio;
488         struct bcm43xx_phyinfo *phy;
489         unsigned long flags;
490         int err = -ENODEV;
491         u16 maxpower;
492
493         wx_enter();
494
495         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
496                 printk(PFX KERN_ERR "TX power not in dBm.\n");
497                 return -EOPNOTSUPP;
498         }
499
500         spin_lock_irqsave(&bcm->lock, flags);
501         if (!bcm->initialized)
502                 goto out_unlock;
503         radio = bcm->current_core->radio;
504         phy = bcm->current_core->phy;
505         if (data->txpower.disabled != (!(radio->enabled))) {
506                 if (data->txpower.disabled)
507                         bcm43xx_radio_turn_off(bcm);
508                 else
509                         bcm43xx_radio_turn_on(bcm);
510         }
511         if (data->txpower.value > 0) {
512                 /* desired and maxpower dBm values are in Q5.2 */
513                 if (phy->type == BCM43xx_PHYTYPE_A)
514                         maxpower = bcm->sprom.maxpower_aphy;
515                 else
516                         maxpower = bcm->sprom.maxpower_bgphy;
517                 radio->txpower_desired = limit_value(data->txpower.value << 2,
518                                                      0, maxpower);
519                 bcm43xx_phy_xmitpower(bcm);
520         }
521         err = 0;
522
523 out_unlock:
524         spin_unlock_irqrestore(&bcm->lock, flags);
525
526         return err;
527 }
528
529 static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
530                                     struct iw_request_info *info,
531                                     union iwreq_data *data,
532                                     char *extra)
533 {
534         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
535         struct bcm43xx_radioinfo *radio;
536         unsigned long flags;
537         int err = -ENODEV;
538
539         wx_enter();
540
541         spin_lock_irqsave(&bcm->lock, flags);
542         if (!bcm->initialized)
543                 goto out_unlock;
544         radio = bcm->current_core->radio;
545         /* desired dBm value is in Q5.2 */
546         data->txpower.value = radio->txpower_desired >> 2;
547         data->txpower.fixed = 1;
548         data->txpower.flags = IW_TXPOW_DBM;
549         data->txpower.disabled = !(radio->enabled);
550
551         err = 0;
552 out_unlock:
553         spin_unlock_irqrestore(&bcm->lock, flags);
554
555         return err;
556 }
557
558 static int bcm43xx_wx_set_retry(struct net_device *net_dev,
559                                 struct iw_request_info *info,
560                                 union iwreq_data *data,
561                                 char *extra)
562 {
563         wx_enter();
564         /*TODO*/
565         return 0;
566 }
567
568 static int bcm43xx_wx_get_retry(struct net_device *net_dev,
569                                 struct iw_request_info *info,
570                                 union iwreq_data *data,
571                                 char *extra)
572 {
573         wx_enter();
574         /*TODO*/
575         return 0;
576 }
577
578 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
579                                    struct iw_request_info *info,
580                                    union iwreq_data *data,
581                                    char *extra)
582 {
583         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
584         int err;
585
586         wx_enter();
587
588         err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
589
590         return err;
591 }
592
593 static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
594                                    struct iw_request_info *info,
595                                    union iwreq_data *data,
596                                    char *extra)
597 {
598         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
599         int err;
600
601         wx_enter();
602
603         err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
604
605         return err;
606 }
607
608 static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
609                                    struct iw_request_info *info,
610                                    union iwreq_data *data,
611                                    char *extra)
612 {
613         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
614         int err;
615
616         wx_enter();
617
618         err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
619
620         return err;
621 }
622
623 static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
624                                    struct iw_request_info *info,
625                                    union iwreq_data *data,
626                                    char *extra)
627 {
628         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
629         int err;
630
631         wx_enter();
632
633         err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
634
635         return err;
636 }
637
638 static int bcm43xx_wx_set_power(struct net_device *net_dev,
639                                 struct iw_request_info *info,
640                                 union iwreq_data *data,
641                                 char *extra)
642 {
643         wx_enter();
644         /*TODO*/
645         return 0;
646 }
647
648 static int bcm43xx_wx_get_power(struct net_device *net_dev,
649                                 struct iw_request_info *info,
650                                 union iwreq_data *data,
651                                 char *extra)
652 {
653         wx_enter();
654         /*TODO*/
655         return 0;
656 }
657
658 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
659                                      struct iw_request_info *info,
660                                      union iwreq_data *data,
661                                      char *extra)
662 {
663         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
664         unsigned long flags;
665         int mode, err = 0;
666
667         wx_enter();
668
669         mode = *((int *)extra);
670         switch (mode) {
671         case 0:
672                 mode = BCM43xx_RADIO_INTERFMODE_NONE;
673                 break;
674         case 1:
675                 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
676                 break;
677         case 2:
678                 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
679                 break;
680         case 3:
681                 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
682                 break;
683         default:
684                 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
685                                     "0 => None,  1 => Non-WLAN,  2 => WLAN,  "
686                                     "3 => Auto-WLAN\n");
687                 return -EINVAL;
688         }
689
690         spin_lock_irqsave(&bcm->lock, flags);
691         if (bcm->initialized) {
692                 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
693                 if (err) {
694                         printk(KERN_ERR PFX "Interference Mitigation not "
695                                             "supported by device\n");
696                 }
697         } else {
698                 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
699                         printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
700                                             "not supported while the interface is down.\n");
701                         err = -ENODEV;
702                 } else
703                         bcm->current_core->radio->interfmode = mode;
704         }
705         spin_unlock_irqrestore(&bcm->lock, flags);
706
707         return err;
708 }
709
710 static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
711                                      struct iw_request_info *info,
712                                      union iwreq_data *data,
713                                      char *extra)
714 {
715         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
716         unsigned long flags;
717         int mode;
718
719         wx_enter();
720
721         spin_lock_irqsave(&bcm->lock, flags);
722         mode = bcm->current_core->radio->interfmode;
723         spin_unlock_irqrestore(&bcm->lock, flags);
724
725         switch (mode) {
726         case BCM43xx_RADIO_INTERFMODE_NONE:
727                 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
728                 break;
729         case BCM43xx_RADIO_INTERFMODE_NONWLAN:
730                 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
731                 break;
732         case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
733                 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
734                 break;
735         default:
736                 assert(0);
737         }
738         data->data.length = strlen(extra) + 1;
739
740         return 0;
741 }
742
743 static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
744                                         struct iw_request_info *info,
745                                         union iwreq_data *data,
746                                         char *extra)
747 {
748         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
749         unsigned long flags;
750         int on;
751
752         wx_enter();
753
754         on = *((int *)extra);
755         spin_lock_irqsave(&bcm->lock, flags);
756         bcm->short_preamble = !!on;
757         spin_unlock_irqrestore(&bcm->lock, flags);
758
759         return 0;
760 }
761
762 static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
763                                         struct iw_request_info *info,
764                                         union iwreq_data *data,
765                                         char *extra)
766 {
767         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
768         unsigned long flags;
769         int on;
770
771         wx_enter();
772
773         spin_lock_irqsave(&bcm->lock, flags);
774         on = bcm->short_preamble;
775         spin_unlock_irqrestore(&bcm->lock, flags);
776
777         if (on)
778                 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
779         else
780                 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
781         data->data.length = strlen(extra) + 1;
782
783         return 0;
784 }
785
786 static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
787                                        struct iw_request_info *info,
788                                        union iwreq_data *data,
789                                        char *extra)
790 {
791         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
792         unsigned long flags;
793         int on;
794         
795         wx_enter();
796         
797         on = *((int *)extra);
798         spin_lock_irqsave(&bcm->lock, flags);
799         bcm->ieee->host_encrypt = !!on;
800         bcm->ieee->host_decrypt = !!on;
801         bcm->ieee->host_build_iv = !on;
802         
803         spin_unlock_irqrestore(&bcm->lock, flags);
804         
805         return 0;
806 }
807
808 static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
809                                        struct iw_request_info *info,
810                                        union iwreq_data *data,
811                                        char *extra)
812 {
813         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
814         unsigned long flags;
815         int on;
816         
817         wx_enter();
818         
819         spin_lock_irqsave(&bcm->lock, flags);
820         on = bcm->ieee->host_encrypt;
821         spin_unlock_irqrestore(&bcm->lock, flags);
822         
823         if (on)
824                 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
825         else
826                 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
827         data->data.length = strlen(extra + 1);
828         
829         return 0;
830 }
831
832 /* Enough buffer to hold a hexdump of the sprom data. */
833 #define SPROM_BUFFERSIZE        512
834
835 static int sprom2hex(const u16 *sprom, char *dump)
836 {
837         int i, pos = 0;
838
839         for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
840                 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
841                                 "%04X", swab16(sprom[i]) & 0xFFFF);
842         }
843
844         return pos + 1;
845 }
846
847 static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
848 {
849         char tmp[5] = { 0 };
850         int cnt = 0;
851         unsigned long parsed;
852         u8 crc, expected_crc;
853
854         if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
855                 return -EINVAL;
856         while (cnt < BCM43xx_SPROM_SIZE) {
857                 memcpy(tmp, dump, 4);
858                 dump += 4;
859                 parsed = simple_strtoul(tmp, NULL, 16);
860                 sprom[cnt++] = swab16((u16)parsed);
861         }
862
863         crc = bcm43xx_sprom_crc(sprom);
864         expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;
865         if (crc != expected_crc) {
866                 printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");
867                 return -EINVAL;
868         }
869
870         return 0;
871 }
872
873 static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
874                                  struct iw_request_info *info,
875                                  union iwreq_data *data,
876                                  char *extra)
877 {
878         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
879         int err = -EPERM, i;
880         u16 *sprom;
881         unsigned long flags;
882
883         if (!capable(CAP_SYS_RAWIO))
884                 goto out;
885
886         err = -ENOMEM;
887         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
888                         GFP_KERNEL);
889         if (!sprom)
890                 goto out;
891
892         spin_lock_irqsave(&bcm->lock, flags);
893         err = -ENODEV;
894         if (!bcm->initialized) {
895                 spin_unlock_irqrestore(&bcm->lock, flags);
896                 goto out_kfree;
897         }
898         for (i = 0; i < BCM43xx_SPROM_SIZE; i++)
899                 sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));
900         spin_unlock_irqrestore(&bcm->lock, flags);
901
902         data->data.length = sprom2hex(sprom, extra);
903
904         err = 0;
905 out_kfree:
906         kfree(sprom);
907 out:
908         return err;
909 }
910
911 static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
912                                   struct iw_request_info *info,
913                                   union iwreq_data *data,
914                                   char *extra)
915 {
916         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
917         int err = -EPERM;
918         u16 *sprom;
919         unsigned long flags;
920         char *input;
921         unsigned int len;
922         u32 spromctl;
923         int i;
924
925         if (!capable(CAP_SYS_RAWIO))
926                 goto out;
927
928         err = -ENOMEM;
929         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
930                         GFP_KERNEL);
931         if (!sprom)
932                 goto out;
933
934         len = data->data.length;
935         extra[len - 1] = '\0';
936         input = strchr(extra, ':');
937         if (input) {
938                 input++;
939                 len -= input - extra;
940         } else
941                 input = extra;
942         err = hex2sprom(sprom, input, len);
943         if (err)
944                 goto out_kfree;
945
946         spin_lock_irqsave(&bcm->lock, flags);
947         err = -ENODEV;
948         if (!bcm->initialized) {
949                 spin_unlock_irqrestore(&bcm->lock, flags);
950                 goto out_kfree;
951         }
952
953         printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
954         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);
955         if (err) {
956                 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
957                 goto out_unlock;
958         }
959         spromctl |= 0x10; /* SPROM WRITE enable. */
960         bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
961         if (err) {
962                 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
963                 goto out_unlock;
964         }
965         /* We must burn lots of CPU cycles here, but that does not
966          * really matter as one does not write the SPROM every other minute...
967          */
968         printk(KERN_INFO PFX "[ 0%%");
969         mdelay(500);
970         for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
971                 if (i == 16)
972                         printk("25%%");
973                 else if (i == 32)
974                         printk("50%%");
975                 else if (i == 48)
976                         printk("75%%");
977                 else if (i % 2)
978                         printk(".");
979 //TODO          bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
980                 mdelay(20);
981         }
982         spromctl &= ~0x10; /* SPROM WRITE enable. */
983         bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);
984         if (err) {
985                 printk(KERN_ERR PFX "Could not access SPROM control register.\n");
986                 goto out_unlock;
987         }
988         mdelay(500);
989         printk("100%% ]\n");
990         printk(KERN_INFO PFX "SPROM written.\n");
991         err = 0;
992 out_unlock:
993         spin_unlock_irqrestore(&bcm->lock, flags);
994 out_kfree:
995         kfree(sprom);
996 out:
997         return err;
998 }
999
1000
1001 #ifdef WX
1002 # undef WX
1003 #endif
1004 #define WX(ioctl)  [(ioctl) - SIOCSIWCOMMIT]
1005 static const iw_handler bcm43xx_wx_handlers[] = {
1006         /* Wireless Identification */
1007         WX(SIOCGIWNAME)         = bcm43xx_wx_get_name,
1008         /* Basic operations */
1009         WX(SIOCSIWFREQ)         = bcm43xx_wx_set_channelfreq,
1010         WX(SIOCGIWFREQ)         = bcm43xx_wx_get_channelfreq,
1011         WX(SIOCSIWMODE)         = bcm43xx_wx_set_mode,
1012         WX(SIOCGIWMODE)         = bcm43xx_wx_get_mode,
1013         /* Informative stuff */
1014         WX(SIOCGIWRANGE)        = bcm43xx_wx_get_rangeparams,
1015         /* Access Point manipulation */
1016         WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
1017         WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
1018         WX(SIOCSIWSCAN)         = ieee80211softmac_wx_trigger_scan,
1019         WX(SIOCGIWSCAN)         = ieee80211softmac_wx_get_scan_results,
1020         /* 802.11 specific support */
1021         WX(SIOCSIWESSID)        = ieee80211softmac_wx_set_essid,
1022         WX(SIOCGIWESSID)        = ieee80211softmac_wx_get_essid,
1023         WX(SIOCSIWNICKN)        = bcm43xx_wx_set_nick,
1024         WX(SIOCGIWNICKN)        = bcm43xx_wx_get_nick,
1025         /* Other parameters */
1026         WX(SIOCSIWRATE)         = ieee80211softmac_wx_set_rate,
1027         WX(SIOCGIWRATE)         = ieee80211softmac_wx_get_rate,
1028         WX(SIOCSIWRTS)          = bcm43xx_wx_set_rts,
1029         WX(SIOCGIWRTS)          = bcm43xx_wx_get_rts,
1030         WX(SIOCSIWFRAG)         = bcm43xx_wx_set_frag,
1031         WX(SIOCGIWFRAG)         = bcm43xx_wx_get_frag,
1032         WX(SIOCSIWTXPOW)        = bcm43xx_wx_set_xmitpower,
1033         WX(SIOCGIWTXPOW)        = bcm43xx_wx_get_xmitpower,
1034 //TODO  WX(SIOCSIWRETRY)        = bcm43xx_wx_set_retry,
1035 //TODO  WX(SIOCGIWRETRY)        = bcm43xx_wx_get_retry,
1036         /* Encoding */
1037         WX(SIOCSIWENCODE)       = bcm43xx_wx_set_encoding,
1038         WX(SIOCGIWENCODE)       = bcm43xx_wx_get_encoding,
1039         WX(SIOCSIWENCODEEXT)    = bcm43xx_wx_set_encodingext,
1040         WX(SIOCGIWENCODEEXT)    = bcm43xx_wx_get_encodingext,
1041         /* Power saving */
1042 //TODO  WX(SIOCSIWPOWER)        = bcm43xx_wx_set_power,
1043 //TODO  WX(SIOCGIWPOWER)        = bcm43xx_wx_get_power,
1044         WX(SIOCSIWGENIE)        = ieee80211softmac_wx_set_genie,
1045         WX(SIOCGIWGENIE)        = ieee80211softmac_wx_get_genie,
1046         WX(SIOCSIWAUTH)         = ieee80211_wx_set_auth,
1047         WX(SIOCGIWAUTH)         = ieee80211_wx_get_auth,
1048 };
1049 #undef WX
1050
1051 static const iw_handler bcm43xx_priv_wx_handlers[] = {
1052         /* Set Interference Mitigation Mode. */
1053         bcm43xx_wx_set_interfmode,
1054         /* Get Interference Mitigation Mode. */
1055         bcm43xx_wx_get_interfmode,
1056         /* Enable/Disable Short Preamble mode. */
1057         bcm43xx_wx_set_shortpreamble,
1058         /* Get Short Preamble mode. */
1059         bcm43xx_wx_get_shortpreamble,
1060         /* Enable/Disable Software Encryption mode */
1061         bcm43xx_wx_set_swencryption,
1062         /* Get Software Encryption mode */
1063         bcm43xx_wx_get_swencryption,
1064         /* Write SRPROM data. */
1065         bcm43xx_wx_sprom_write,
1066         /* Read SPROM data. */
1067         bcm43xx_wx_sprom_read,
1068 };
1069
1070 #define PRIV_WX_SET_INTERFMODE          (SIOCIWFIRSTPRIV + 0)
1071 #define PRIV_WX_GET_INTERFMODE          (SIOCIWFIRSTPRIV + 1)
1072 #define PRIV_WX_SET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 2)
1073 #define PRIV_WX_GET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 3)
1074 #define PRIV_WX_SET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 4)
1075 #define PRIV_WX_GET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 5)
1076 #define PRIV_WX_SPROM_WRITE             (SIOCIWFIRSTPRIV + 6)
1077 #define PRIV_WX_SPROM_READ              (SIOCIWFIRSTPRIV + 7)
1078
1079 #define PRIV_WX_DUMMY(ioctl)    \
1080         {                                       \
1081                 .cmd            = (ioctl),      \
1082                 .name           = "__unused"    \
1083         }
1084
1085 static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
1086         {
1087                 .cmd            = PRIV_WX_SET_INTERFMODE,
1088                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1089                 .name           = "set_interfmode",
1090         },
1091         {
1092                 .cmd            = PRIV_WX_GET_INTERFMODE,
1093                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1094                 .name           = "get_interfmode",
1095         },
1096         {
1097                 .cmd            = PRIV_WX_SET_SHORTPREAMBLE,
1098                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1099                 .name           = "set_shortpreambl",
1100         },
1101         {
1102                 .cmd            = PRIV_WX_GET_SHORTPREAMBLE,
1103                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1104                 .name           = "get_shortpreambl",
1105         },
1106         {
1107                 .cmd            = PRIV_WX_SET_SWENCRYPTION,
1108                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1109                 .name           = "set_swencryption",
1110         },
1111         {
1112                 .cmd            = PRIV_WX_GET_SWENCRYPTION,
1113                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
1114                 .name           = "get_swencryption",
1115         },
1116         {
1117                 .cmd            = PRIV_WX_SPROM_WRITE,
1118                 .set_args       = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
1119                 .name           = "write_sprom",
1120         },
1121         {
1122                 .cmd            = PRIV_WX_SPROM_READ,
1123                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
1124                 .name           = "read_sprom",
1125         },
1126 };
1127
1128 const struct iw_handler_def bcm43xx_wx_handlers_def = {
1129         .standard               = bcm43xx_wx_handlers,
1130         .num_standard           = ARRAY_SIZE(bcm43xx_wx_handlers),
1131         .num_private            = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
1132         .num_private_args       = ARRAY_SIZE(bcm43xx_priv_wx_args),
1133         .private                = bcm43xx_priv_wx_handlers,
1134         .private_args           = bcm43xx_priv_wx_args,
1135 };
1136
1137 /* vim: set ts=8 sw=8 sts=8: */