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