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