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