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