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