3   Broadcom BCM43xx wireless driver
 
   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>
 
  11   Some parts of the code in this file are derived from the ipw2200
 
  12   driver  Copyright(c) 2003 - 2004 Intel Corporation.
 
  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.
 
  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.
 
  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.
 
  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>
 
  40 #include "bcm43xx_wx.h"
 
  41 #include "bcm43xx_main.h"
 
  42 #include "bcm43xx_radio.h"
 
  43 #include "bcm43xx_phy.h"
 
  46 /* The WIRELESS_EXT version, which is implemented by this driver. */
 
  47 #define BCM43xx_WX_VERSION      18
 
  49 #define MAX_WX_STRING           80
 
  51 static int bcm43xx_wx_get_name(struct net_device *net_dev,
 
  52                                struct iw_request_info *info,
 
  53                                union iwreq_data *data,
 
  56         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
  58         struct bcm43xx_phyinfo *phy;
 
  59         char suffix[7] = { 0 };
 
  60         int have_a = 0, have_b = 0, have_g = 0;
 
  62         mutex_lock(&bcm->mutex);
 
  63         for (i = 0; i < bcm->nr_80211_available; i++) {
 
  64                 phy = &(bcm->core_80211_ext[i].phy);
 
  66                 case BCM43xx_PHYTYPE_A:
 
  69                 case BCM43xx_PHYTYPE_G:
 
  71                 case BCM43xx_PHYTYPE_B:
 
  78         mutex_unlock(&bcm->mutex);
 
  96         snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
 
 101 static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
 
 102                                       struct iw_request_info *info,
 
 103                                       union iwreq_data *data,
 
 106         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 112         mutex_lock(&bcm->mutex);
 
 113         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 115         if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
 
 116                 channel = data->freq.m;
 
 117                 freq = bcm43xx_channel_to_freq(bcm, channel);
 
 119                 channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
 
 122         if (!ieee80211_is_valid_channel(bcm->ieee, channel))
 
 124         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 
 125                 //ieee80211softmac_disassoc(softmac, $REASON);
 
 126                 bcm43xx_mac_suspend(bcm);
 
 127                 err = bcm43xx_radio_selectchannel(bcm, channel, 0);
 
 128                 bcm43xx_mac_enable(bcm);
 
 130                 bcm43xx_current_radio(bcm)->initial_channel = channel;
 
 134         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 135         mutex_unlock(&bcm->mutex);
 
 140 static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
 
 141                                       struct iw_request_info *info,
 
 142                                       union iwreq_data *data,
 
 145         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 146         struct bcm43xx_radioinfo *radio;
 
 150         mutex_lock(&bcm->mutex);
 
 151         radio = bcm43xx_current_radio(bcm);
 
 152         channel = radio->channel;
 
 153         if (channel == 0xFF) {
 
 154                 channel = radio->initial_channel;
 
 158         assert(channel > 0 && channel <= 1000);
 
 160         data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
 
 161         data->freq.flags = 1;
 
 165         mutex_unlock(&bcm->mutex);
 
 170 static int bcm43xx_wx_set_mode(struct net_device *net_dev,
 
 171                                struct iw_request_info *info,
 
 172                                union iwreq_data *data,
 
 175         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 180         if (mode == IW_MODE_AUTO)
 
 181                 mode = BCM43xx_INITIAL_IWMODE;
 
 183         mutex_lock(&bcm->mutex);
 
 184         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 185         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 
 186                 if (bcm->ieee->iw_mode != mode)
 
 187                         bcm43xx_set_iwmode(bcm, mode);
 
 189                 bcm->ieee->iw_mode = mode;
 
 190         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 191         mutex_unlock(&bcm->mutex);
 
 196 static int bcm43xx_wx_get_mode(struct net_device *net_dev,
 
 197                                struct iw_request_info *info,
 
 198                                union iwreq_data *data,
 
 201         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 203         mutex_lock(&bcm->mutex);
 
 204         data->mode = bcm->ieee->iw_mode;
 
 205         mutex_unlock(&bcm->mutex);
 
 210 static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 
 211                                       struct iw_request_info *info,
 
 212                                       union iwreq_data *data,
 
 215         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 216         struct iw_range *range = (struct iw_range *)extra;
 
 217         const struct ieee80211_geo *geo;
 
 219         struct bcm43xx_phyinfo *phy;
 
 221         data->data.length = sizeof(*range);
 
 222         memset(range, 0, sizeof(*range));
 
 224         //TODO: What about 802.11b?
 
 225         /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
 
 226         range->throughput = 27 * 1000 * 1000;
 
 228         range->max_qual.qual = 100;
 
 229         range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
 
 230         range->max_qual.noise = 146;
 
 231         range->max_qual.updated = IW_QUAL_ALL_UPDATED;
 
 233         range->avg_qual.qual = 50;
 
 234         range->avg_qual.level = 0;
 
 235         range->avg_qual.noise = 0;
 
 236         range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
 
 238         range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
 
 239         range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
 
 240         range->min_frag = MIN_FRAG_THRESHOLD;
 
 241         range->max_frag = MAX_FRAG_THRESHOLD;
 
 243         range->encoding_size[0] = 5;
 
 244         range->encoding_size[1] = 13;
 
 245         range->num_encoding_sizes = 2;
 
 246         range->max_encoding_tokens = WEP_KEYS;
 
 248         range->we_version_compiled = WIRELESS_EXT;
 
 249         range->we_version_source = BCM43xx_WX_VERSION;
 
 251         range->enc_capa = IW_ENC_CAPA_WPA |
 
 253                           IW_ENC_CAPA_CIPHER_TKIP |
 
 254                           IW_ENC_CAPA_CIPHER_CCMP;
 
 256         mutex_lock(&bcm->mutex);
 
 257         phy = bcm43xx_current_phy(bcm);
 
 259         range->num_bitrates = 0;
 
 261         if (phy->type == BCM43xx_PHYTYPE_A ||
 
 262             phy->type == BCM43xx_PHYTYPE_G) {
 
 263                 range->num_bitrates = 8;
 
 264                 range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
 
 265                 range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
 
 266                 range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
 
 267                 range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
 
 268                 range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
 
 269                 range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
 
 270                 range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
 
 271                 range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
 
 273         if (phy->type == BCM43xx_PHYTYPE_B ||
 
 274             phy->type == BCM43xx_PHYTYPE_G) {
 
 275                 range->num_bitrates += 4;
 
 276                 range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
 
 277                 range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
 
 278                 range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
 
 279                 range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
 
 282         geo = ieee80211_get_geo(bcm->ieee);
 
 283         range->num_channels = geo->a_channels + geo->bg_channels;
 
 285         for (i = 0; i < geo->a_channels; i++) {
 
 286                 if (j == IW_MAX_FREQUENCIES)
 
 288                 range->freq[j].i = j + 1;
 
 289                 range->freq[j].m = geo->a[i].freq;//FIXME?
 
 290                 range->freq[j].e = 1;
 
 293         for (i = 0; i < geo->bg_channels; i++) {
 
 294                 if (j == IW_MAX_FREQUENCIES)
 
 296                 range->freq[j].i = j + 1;
 
 297                 range->freq[j].m = geo->bg[i].freq;//FIXME?
 
 298                 range->freq[j].e = 1;
 
 301         range->num_frequency = j;
 
 303         mutex_unlock(&bcm->mutex);
 
 308 static int bcm43xx_wx_set_nick(struct net_device *net_dev,
 
 309                                struct iw_request_info *info,
 
 310                                union iwreq_data *data,
 
 313         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 316         mutex_lock(&bcm->mutex);
 
 317         len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
 
 318         memcpy(bcm->nick, extra, len);
 
 319         bcm->nick[len] = '\0';
 
 320         mutex_unlock(&bcm->mutex);
 
 325 static int bcm43xx_wx_get_nick(struct net_device *net_dev,
 
 326                                struct iw_request_info *info,
 
 327                                union iwreq_data *data,
 
 330         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 333         mutex_lock(&bcm->mutex);
 
 334         len = strlen(bcm->nick);
 
 335         memcpy(extra, bcm->nick, len);
 
 336         data->data.length = (__u16)len;
 
 337         data->data.flags = 1;
 
 338         mutex_unlock(&bcm->mutex);
 
 343 static int bcm43xx_wx_set_rts(struct net_device *net_dev,
 
 344                               struct iw_request_info *info,
 
 345                               union iwreq_data *data,
 
 348         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 352         mutex_lock(&bcm->mutex);
 
 353         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 354         if (data->rts.disabled) {
 
 355                 bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
 
 358                 if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
 
 359                     data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
 
 360                         bcm->rts_threshold = data->rts.value;
 
 364         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 365         mutex_unlock(&bcm->mutex);
 
 370 static int bcm43xx_wx_get_rts(struct net_device *net_dev,
 
 371                               struct iw_request_info *info,
 
 372                               union iwreq_data *data,
 
 375         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 377         mutex_lock(&bcm->mutex);
 
 378         data->rts.value = bcm->rts_threshold;
 
 380         data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
 
 381         mutex_unlock(&bcm->mutex);
 
 386 static int bcm43xx_wx_set_frag(struct net_device *net_dev,
 
 387                                struct iw_request_info *info,
 
 388                                union iwreq_data *data,
 
 391         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 395         mutex_lock(&bcm->mutex);
 
 396         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 397         if (data->frag.disabled) {
 
 398                 bcm->ieee->fts = MAX_FRAG_THRESHOLD;
 
 401                 if (data->frag.value >= MIN_FRAG_THRESHOLD &&
 
 402                     data->frag.value <= MAX_FRAG_THRESHOLD) {
 
 403                         bcm->ieee->fts = data->frag.value & ~0x1;
 
 407         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 408         mutex_unlock(&bcm->mutex);
 
 413 static int bcm43xx_wx_get_frag(struct net_device *net_dev,
 
 414                                struct iw_request_info *info,
 
 415                                union iwreq_data *data,
 
 418         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 420         mutex_lock(&bcm->mutex);
 
 421         data->frag.value = bcm->ieee->fts;
 
 422         data->frag.fixed = 0;
 
 423         data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
 
 424         mutex_unlock(&bcm->mutex);
 
 429 static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
 
 430                                     struct iw_request_info *info,
 
 431                                     union iwreq_data *data,
 
 434         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 435         struct bcm43xx_radioinfo *radio;
 
 436         struct bcm43xx_phyinfo *phy;
 
 441         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
 
 442                 printk(PFX KERN_ERR "TX power not in dBm.\n");
 
 446         mutex_lock(&bcm->mutex);
 
 447         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 448         if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 
 450         radio = bcm43xx_current_radio(bcm);
 
 451         phy = bcm43xx_current_phy(bcm);
 
 452         if (data->txpower.disabled != (!(radio->enabled))) {
 
 453                 if (data->txpower.disabled)
 
 454                         bcm43xx_radio_turn_off(bcm);
 
 456                         bcm43xx_radio_turn_on(bcm);
 
 458         if (data->txpower.value > 0) {
 
 459                 /* desired and maxpower dBm values are in Q5.2 */
 
 460                 if (phy->type == BCM43xx_PHYTYPE_A)
 
 461                         maxpower = bcm->sprom.maxpower_aphy;
 
 463                         maxpower = bcm->sprom.maxpower_bgphy;
 
 464                 radio->txpower_desired = limit_value(data->txpower.value << 2,
 
 466                 bcm43xx_phy_xmitpower(bcm);
 
 471         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 472         mutex_unlock(&bcm->mutex);
 
 477 static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
 
 478                                     struct iw_request_info *info,
 
 479                                     union iwreq_data *data,
 
 482         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 483         struct bcm43xx_radioinfo *radio;
 
 486         mutex_lock(&bcm->mutex);
 
 487         if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 
 489         radio = bcm43xx_current_radio(bcm);
 
 490         /* desired dBm value is in Q5.2 */
 
 491         data->txpower.value = radio->txpower_desired >> 2;
 
 492         data->txpower.fixed = 1;
 
 493         data->txpower.flags = IW_TXPOW_DBM;
 
 494         data->txpower.disabled = !(radio->enabled);
 
 498         mutex_unlock(&bcm->mutex);
 
 503 static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
 
 504                                    struct iw_request_info *info,
 
 505                                    union iwreq_data *data,
 
 508         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 511         err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
 
 516 static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
 
 517                                    struct iw_request_info *info,
 
 518                                    union iwreq_data *data,
 
 521         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 524         err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
 
 529 static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
 
 530                                    struct iw_request_info *info,
 
 531                                    union iwreq_data *data,
 
 534         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 537         err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
 
 542 static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
 
 543                                    struct iw_request_info *info,
 
 544                                    union iwreq_data *data,
 
 547         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 550         err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
 
 555 static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
 
 556                                      struct iw_request_info *info,
 
 557                                      union iwreq_data *data,
 
 560         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 564         mode = *((int *)extra);
 
 567                 mode = BCM43xx_RADIO_INTERFMODE_NONE;
 
 570                 mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
 
 573                 mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
 
 576                 mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
 
 579                 printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
 
 580                                     "0 => None,  1 => Non-WLAN,  2 => WLAN,  "
 
 585         mutex_lock(&bcm->mutex);
 
 586         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 587         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 
 588                 err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 
 590                         printk(KERN_ERR PFX "Interference Mitigation not "
 
 591                                             "supported by device\n");
 
 594                 if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
 
 595                         printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
 
 596                                             "not supported while the interface is down.\n");
 
 599                         bcm43xx_current_radio(bcm)->interfmode = mode;
 
 601         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 602         mutex_unlock(&bcm->mutex);
 
 607 static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
 
 608                                      struct iw_request_info *info,
 
 609                                      union iwreq_data *data,
 
 612         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 615         mutex_lock(&bcm->mutex);
 
 616         mode = bcm43xx_current_radio(bcm)->interfmode;
 
 617         mutex_unlock(&bcm->mutex);
 
 620         case BCM43xx_RADIO_INTERFMODE_NONE:
 
 621                 strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
 
 623         case BCM43xx_RADIO_INTERFMODE_NONWLAN:
 
 624                 strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
 
 626         case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
 
 627                 strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
 
 632         data->data.length = strlen(extra) + 1;
 
 637 static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
 
 638                                         struct iw_request_info *info,
 
 639                                         union iwreq_data *data,
 
 642         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 646         on = *((int *)extra);
 
 647         mutex_lock(&bcm->mutex);
 
 648         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 649         bcm->short_preamble = !!on;
 
 650         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 651         mutex_unlock(&bcm->mutex);
 
 656 static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
 
 657                                         struct iw_request_info *info,
 
 658                                         union iwreq_data *data,
 
 661         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 664         mutex_lock(&bcm->mutex);
 
 665         on = bcm->short_preamble;
 
 666         mutex_unlock(&bcm->mutex);
 
 669                 strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
 
 671                 strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
 
 672         data->data.length = strlen(extra) + 1;
 
 677 static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
 
 678                                        struct iw_request_info *info,
 
 679                                        union iwreq_data *data,
 
 682         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 686         on = *((int *)extra);
 
 688         mutex_lock(&bcm->mutex);
 
 689         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 690         bcm->ieee->host_encrypt = !!on;
 
 691         bcm->ieee->host_decrypt = !!on;
 
 692         bcm->ieee->host_build_iv = !on;
 
 693         bcm->ieee->host_strip_iv_icv = !on;
 
 694         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 695         mutex_unlock(&bcm->mutex);
 
 700 static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
 
 701                                        struct iw_request_info *info,
 
 702                                        union iwreq_data *data,
 
 705         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 708         mutex_lock(&bcm->mutex);
 
 709         on = bcm->ieee->host_encrypt;
 
 710         mutex_unlock(&bcm->mutex);
 
 713                 strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
 
 715                 strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
 
 716         data->data.length = strlen(extra + 1);
 
 721 /* Enough buffer to hold a hexdump of the sprom data. */
 
 722 #define SPROM_BUFFERSIZE        512
 
 724 static int sprom2hex(const u16 *sprom, char *dump)
 
 728         for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
 
 729                 pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
 
 730                                 "%04X", swab16(sprom[i]) & 0xFFFF);
 
 736 static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
 
 740         unsigned long parsed;
 
 742         if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
 
 744         while (cnt < BCM43xx_SPROM_SIZE) {
 
 745                 memcpy(tmp, dump, 4);
 
 747                 parsed = simple_strtoul(tmp, NULL, 16);
 
 748                 sprom[cnt++] = swab16((u16)parsed);
 
 754 static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
 
 755                                  struct iw_request_info *info,
 
 756                                  union iwreq_data *data,
 
 759         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 764         if (!capable(CAP_SYS_RAWIO))
 
 768         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
 
 773         mutex_lock(&bcm->mutex);
 
 774         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 776         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 
 777                 err = bcm43xx_sprom_read(bcm, sprom);
 
 778         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 779         mutex_unlock(&bcm->mutex);
 
 781                 data->data.length = sprom2hex(sprom, extra);
 
 787 static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
 
 788                                   struct iw_request_info *info,
 
 789                                   union iwreq_data *data,
 
 792         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 799         if (!capable(CAP_SYS_RAWIO))
 
 803         sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
 
 808         len = data->data.length;
 
 809         extra[len - 1] = '\0';
 
 810         input = strchr(extra, ':');
 
 813                 len -= input - extra;
 
 816         err = hex2sprom(sprom, input, len);
 
 820         mutex_lock(&bcm->mutex);
 
 821         spin_lock_irqsave(&bcm->irq_lock, flags);
 
 822         spin_lock(&bcm->leds_lock);
 
 824         if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 
 825                 err = bcm43xx_sprom_write(bcm, sprom);
 
 826         spin_unlock(&bcm->leds_lock);
 
 827         spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 828         mutex_unlock(&bcm->mutex);
 
 835 /* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
 
 837 static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
 
 839         struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 
 840         struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
 
 841         struct iw_statistics *wstats;
 
 842         struct ieee80211_network *network = NULL;
 
 843         static int tmp_level = 0;
 
 844         static int tmp_qual = 0;
 
 847         wstats = &bcm->stats.wstats;
 
 848         if (!mac->associnfo.associated) {
 
 849                 wstats->miss.beacon = 0;
 
 850 //              bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
 
 851                 wstats->discard.retries = 0;
 
 852 //              bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
 
 853                 wstats->discard.nwid = 0;
 
 854 //              bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
 
 855                 wstats->discard.code = 0;
 
 856 //              bcm->ieee->ieee_stats.rx_fragments = 0;  // FIXME: same here
 
 857                 wstats->discard.fragment = 0;
 
 858                 wstats->discard.misc = 0;
 
 859                 wstats->qual.qual = 0;
 
 860                 wstats->qual.level = 0;
 
 861                 wstats->qual.noise = 0;
 
 862                 wstats->qual.updated = 7;
 
 863                 wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 
 866         /* fill in the real statistics when iface associated */
 
 867         spin_lock_irqsave(&mac->ieee->lock, flags);
 
 868         list_for_each_entry(network, &mac->ieee->network_list, list) {
 
 869                 if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
 
 870                         if (!tmp_level) {       /* get initial values */
 
 871                                 tmp_level = network->stats.signal;
 
 872                                 tmp_qual = network->stats.rssi;
 
 873                         } else {                /* smooth results */
 
 874                                 tmp_level = (15 * tmp_level + network->stats.signal)/16;
 
 875                                 tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
 
 880         spin_unlock_irqrestore(&mac->ieee->lock, flags);
 
 881         wstats->qual.level = tmp_level;
 
 882         wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
 
 883         wstats->qual.noise = bcm->stats.noise;
 
 884         wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 
 885         wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
 
 886         wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
 
 887         wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
 
 888         wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
 
 889         wstats->discard.misc = 0;       // FIXME
 
 890         wstats->miss.beacon = 0;        // FIXME
 
 898 #define WX(ioctl)  [(ioctl) - SIOCSIWCOMMIT]
 
 899 static const iw_handler bcm43xx_wx_handlers[] = {
 
 900         /* Wireless Identification */
 
 901         WX(SIOCGIWNAME)         = bcm43xx_wx_get_name,
 
 902         /* Basic operations */
 
 903         WX(SIOCSIWFREQ)         = bcm43xx_wx_set_channelfreq,
 
 904         WX(SIOCGIWFREQ)         = bcm43xx_wx_get_channelfreq,
 
 905         WX(SIOCSIWMODE)         = bcm43xx_wx_set_mode,
 
 906         WX(SIOCGIWMODE)         = bcm43xx_wx_get_mode,
 
 907         /* Informative stuff */
 
 908         WX(SIOCGIWRANGE)        = bcm43xx_wx_get_rangeparams,
 
 909         /* Access Point manipulation */
 
 910         WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
 
 911         WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
 
 912         WX(SIOCSIWSCAN)         = ieee80211softmac_wx_trigger_scan,
 
 913         WX(SIOCGIWSCAN)         = ieee80211softmac_wx_get_scan_results,
 
 914         /* 802.11 specific support */
 
 915         WX(SIOCSIWESSID)        = ieee80211softmac_wx_set_essid,
 
 916         WX(SIOCGIWESSID)        = ieee80211softmac_wx_get_essid,
 
 917         WX(SIOCSIWNICKN)        = bcm43xx_wx_set_nick,
 
 918         WX(SIOCGIWNICKN)        = bcm43xx_wx_get_nick,
 
 919         /* Other parameters */
 
 920         WX(SIOCSIWRATE)         = ieee80211softmac_wx_set_rate,
 
 921         WX(SIOCGIWRATE)         = ieee80211softmac_wx_get_rate,
 
 922         WX(SIOCSIWRTS)          = bcm43xx_wx_set_rts,
 
 923         WX(SIOCGIWRTS)          = bcm43xx_wx_get_rts,
 
 924         WX(SIOCSIWFRAG)         = bcm43xx_wx_set_frag,
 
 925         WX(SIOCGIWFRAG)         = bcm43xx_wx_get_frag,
 
 926         WX(SIOCSIWTXPOW)        = bcm43xx_wx_set_xmitpower,
 
 927         WX(SIOCGIWTXPOW)        = bcm43xx_wx_get_xmitpower,
 
 928 //TODO  WX(SIOCSIWRETRY)        = bcm43xx_wx_set_retry,
 
 929 //TODO  WX(SIOCGIWRETRY)        = bcm43xx_wx_get_retry,
 
 931         WX(SIOCSIWENCODE)       = bcm43xx_wx_set_encoding,
 
 932         WX(SIOCGIWENCODE)       = bcm43xx_wx_get_encoding,
 
 933         WX(SIOCSIWENCODEEXT)    = bcm43xx_wx_set_encodingext,
 
 934         WX(SIOCGIWENCODEEXT)    = bcm43xx_wx_get_encodingext,
 
 936 //TODO  WX(SIOCSIWPOWER)        = bcm43xx_wx_set_power,
 
 937 //TODO  WX(SIOCGIWPOWER)        = bcm43xx_wx_get_power,
 
 938         WX(SIOCSIWGENIE)        = ieee80211softmac_wx_set_genie,
 
 939         WX(SIOCGIWGENIE)        = ieee80211softmac_wx_get_genie,
 
 940         WX(SIOCSIWAUTH)         = ieee80211_wx_set_auth,
 
 941         WX(SIOCGIWAUTH)         = ieee80211_wx_get_auth,
 
 945 static const iw_handler bcm43xx_priv_wx_handlers[] = {
 
 946         /* Set Interference Mitigation Mode. */
 
 947         bcm43xx_wx_set_interfmode,
 
 948         /* Get Interference Mitigation Mode. */
 
 949         bcm43xx_wx_get_interfmode,
 
 950         /* Enable/Disable Short Preamble mode. */
 
 951         bcm43xx_wx_set_shortpreamble,
 
 952         /* Get Short Preamble mode. */
 
 953         bcm43xx_wx_get_shortpreamble,
 
 954         /* Enable/Disable Software Encryption mode */
 
 955         bcm43xx_wx_set_swencryption,
 
 956         /* Get Software Encryption mode */
 
 957         bcm43xx_wx_get_swencryption,
 
 958         /* Write SRPROM data. */
 
 959         bcm43xx_wx_sprom_write,
 
 960         /* Read SPROM data. */
 
 961         bcm43xx_wx_sprom_read,
 
 964 #define PRIV_WX_SET_INTERFMODE          (SIOCIWFIRSTPRIV + 0)
 
 965 #define PRIV_WX_GET_INTERFMODE          (SIOCIWFIRSTPRIV + 1)
 
 966 #define PRIV_WX_SET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 2)
 
 967 #define PRIV_WX_GET_SHORTPREAMBLE       (SIOCIWFIRSTPRIV + 3)
 
 968 #define PRIV_WX_SET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 4)
 
 969 #define PRIV_WX_GET_SWENCRYPTION        (SIOCIWFIRSTPRIV + 5)
 
 970 #define PRIV_WX_SPROM_WRITE             (SIOCIWFIRSTPRIV + 6)
 
 971 #define PRIV_WX_SPROM_READ              (SIOCIWFIRSTPRIV + 7)
 
 973 #define PRIV_WX_DUMMY(ioctl)    \
 
 979 static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
 
 981                 .cmd            = PRIV_WX_SET_INTERFMODE,
 
 982                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
 983                 .name           = "set_interfmode",
 
 986                 .cmd            = PRIV_WX_GET_INTERFMODE,
 
 987                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
 
 988                 .name           = "get_interfmode",
 
 991                 .cmd            = PRIV_WX_SET_SHORTPREAMBLE,
 
 992                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
 993                 .name           = "set_shortpreamb",
 
 996                 .cmd            = PRIV_WX_GET_SHORTPREAMBLE,
 
 997                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
 
 998                 .name           = "get_shortpreamb",
 
1001                 .cmd            = PRIV_WX_SET_SWENCRYPTION,
 
1002                 .set_args       = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 
1003                 .name           = "set_swencrypt",
 
1006                 .cmd            = PRIV_WX_GET_SWENCRYPTION,
 
1007                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
 
1008                 .name           = "get_swencrypt",
 
1011                 .cmd            = PRIV_WX_SPROM_WRITE,
 
1012                 .set_args       = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
 
1013                 .name           = "write_sprom",
 
1016                 .cmd            = PRIV_WX_SPROM_READ,
 
1017                 .get_args       = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
 
1018                 .name           = "read_sprom",
 
1022 const struct iw_handler_def bcm43xx_wx_handlers_def = {
 
1023         .standard               = bcm43xx_wx_handlers,
 
1024         .num_standard           = ARRAY_SIZE(bcm43xx_wx_handlers),
 
1025         .num_private            = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
 
1026         .num_private_args       = ARRAY_SIZE(bcm43xx_priv_wx_args),
 
1027         .private                = bcm43xx_priv_wx_handlers,
 
1028         .private_args           = bcm43xx_priv_wx_args,
 
1029         .get_wireless_stats     = bcm43xx_get_wireless_stats,