mwifiex: remove global user_scan_cfg variable
[cascardo/linux.git] / drivers / net / wireless / mwifiex / cfg80211.c
index e498dbf..4dcb8fb 100644 (file)
@@ -527,6 +527,41 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
        return mwifiex_set_rf_channel(priv, chan, channel_type);
 }
 
+static int
+mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
+{
+       struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct mwifiex_ds_ant_cfg ant_cfg;
+
+       if (!tx_ant || !rx_ant)
+               return -EOPNOTSUPP;
+
+       if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) {
+               /* Not a MIMO chip. User should provide specific antenna number
+                * for Tx/Rx path or enable all antennas for diversity
+                */
+               if (tx_ant != rx_ant)
+                       return -EOPNOTSUPP;
+
+               if ((tx_ant & (tx_ant - 1)) &&
+                   (tx_ant != BIT(adapter->number_of_antenna) - 1))
+                       return -EOPNOTSUPP;
+
+               if ((tx_ant == BIT(adapter->number_of_antenna) - 1) &&
+                   (priv->adapter->number_of_antenna > 1)) {
+                       tx_ant = RF_ANTENNA_AUTO;
+                       rx_ant = RF_ANTENNA_AUTO;
+               }
+       }
+
+       ant_cfg.tx_ant = tx_ant;
+       ant_cfg.rx_ant = rx_ant;
+
+       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA,
+                                    HostCmd_ACT_GEN_SET, 0, &ant_cfg);
+}
+
 /*
  * This function sets the fragmentation threshold.
  *
@@ -883,8 +918,8 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = {
 /*
  * CFG802.11 operation handler for setting bit rates.
  *
- * Function selects legacy bang B/G/BG from corresponding bitrates selection.
- * Currently only 2.4GHz band is supported.
+ * Function configures data rates to firmware using bitrate mask
+ * provided by cfg80211.
  */
 static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
                                struct net_device *dev,
@@ -892,43 +927,36 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
                                const struct cfg80211_bitrate_mask *mask)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
-       int index = 0, mode = 0, i;
-       struct mwifiex_adapter *adapter = priv->adapter;
+       u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+       enum ieee80211_band band;
 
-       /* Currently only 2.4GHz is supported */
-       for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) {
-               /*
-                * Rates below 6 Mbps in the table are CCK rates; 802.11b
-                * and from 6 they are OFDM; 802.11G
-                */
-               if (mwifiex_rates[i].bitrate == 60) {
-                       index = 1 << i;
-                       break;
-               }
+       if (!priv->media_connected) {
+               dev_err(priv->adapter->dev,
+                       "Can not set Tx data rate in disconnected state\n");
+               return -EINVAL;
        }
 
-       if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) {
-               mode = BAND_B;
-       } else {
-               mode = BAND_G;
-               if (mask->control[IEEE80211_BAND_2GHZ].legacy % index)
-                       mode |=  BAND_B;
-       }
+       band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
 
-       if (!((mode | adapter->fw_bands) & ~adapter->fw_bands)) {
-               adapter->config_bands = mode;
-               if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
-                       adapter->adhoc_start_band = mode;
-                       adapter->adhoc_11n_enabled = false;
-               }
-       }
-       adapter->sec_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
-       adapter->channel_type = NL80211_CHAN_NO_HT;
+       memset(bitmap_rates, 0, sizeof(bitmap_rates));
 
-       wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n",
-                   (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : "");
+       /* Fill HR/DSSS rates. */
+       if (band == IEEE80211_BAND_2GHZ)
+               bitmap_rates[0] = mask->control[band].legacy & 0x000f;
 
-       return 0;
+       /* Fill OFDM rates */
+       if (band == IEEE80211_BAND_2GHZ)
+               bitmap_rates[1] = (mask->control[band].legacy & 0x0ff0) >> 4;
+       else
+               bitmap_rates[1] = mask->control[band].legacy;
+
+       /* Fill MCS rates */
+       bitmap_rates[2] = mask->control[band].mcs[0];
+       if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2)
+               bitmap_rates[2] |= mask->control[band].mcs[1] << 8;
+
+       return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
+                                    HostCmd_ACT_GEN_SET, 0, bitmap_rates);
 }
 
 /*
@@ -1324,6 +1352,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        int i, ret;
        struct ieee80211_channel *chan;
+       struct mwifiex_user_scan_cfg *user_scan_cfg;
 
        wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
 
@@ -1334,22 +1363,24 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
                return -EBUSY;
        }
 
-       if (priv->user_scan_cfg) {
+       /* Block scan request if scan operation or scan cleanup when interface
+        * is disabled is in process
+        */
+       if (priv->scan_request || priv->scan_aborting) {
                dev_err(priv->adapter->dev, "cmd: Scan already in process..\n");
                return -EBUSY;
        }
 
-       priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
-                                     GFP_KERNEL);
-       if (!priv->user_scan_cfg) {
+       user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
+       if (!user_scan_cfg) {
                dev_err(priv->adapter->dev, "failed to alloc scan_req\n");
                return -ENOMEM;
        }
 
        priv->scan_request = request;
 
-       priv->user_scan_cfg->num_ssids = request->n_ssids;
-       priv->user_scan_cfg->ssid_list = request->ssids;
+       user_scan_cfg->num_ssids = request->n_ssids;
+       user_scan_cfg->ssid_list = request->ssids;
 
        if (request->ie && request->ie_len) {
                for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
@@ -1364,25 +1395,25 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
 
        for (i = 0; i < request->n_channels; i++) {
                chan = request->channels[i];
-               priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
-               priv->user_scan_cfg->chan_list[i].radio_type = chan->band;
+               user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
+               user_scan_cfg->chan_list[i].radio_type = chan->band;
 
                if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       priv->user_scan_cfg->chan_list[i].scan_type =
+                       user_scan_cfg->chan_list[i].scan_type =
                                                MWIFIEX_SCAN_TYPE_PASSIVE;
                else
-                       priv->user_scan_cfg->chan_list[i].scan_type =
+                       user_scan_cfg->chan_list[i].scan_type =
                                                MWIFIEX_SCAN_TYPE_ACTIVE;
 
-               priv->user_scan_cfg->chan_list[i].scan_time = 0;
+               user_scan_cfg->chan_list[i].scan_time = 0;
        }
 
-       ret = mwifiex_scan_networks(priv, priv->user_scan_cfg);
+       ret = mwifiex_scan_networks(priv, user_scan_cfg);
+       kfree(user_scan_cfg);
        if (ret) {
                dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+               priv->scan_aborting = false;
                priv->scan_request = NULL;
-               kfree(priv->user_scan_cfg);
-               priv->user_scan_cfg = NULL;
                return ret;
        }
 
@@ -1518,8 +1549,8 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                return ERR_PTR(-EINVAL);
        }
 
-       dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
-                             ether_setup, 1);
+       dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name,
+                              ether_setup, IEEE80211_NUM_ACS, 1);
        if (!dev) {
                wiphy_err(wiphy, "no memory available for netdevice\n");
                priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -1575,8 +1606,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
        mwifiex_dev_debugfs_remove(priv);
 #endif
 
-       if (!netif_queue_stopped(priv->netdev))
-               netif_stop_queue(priv->netdev);
+       mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
 
        if (netif_carrier_ok(priv->netdev))
                netif_carrier_off(priv->netdev);
@@ -1584,9 +1614,6 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
        if (dev->reg_state == NETREG_REGISTERED)
                unregister_netdevice(dev);
 
-       if (dev->reg_state == NETREG_UNREGISTERED)
-               free_netdev(dev);
-
        /* Clear the priv in adapter */
        priv->netdev = NULL;
 
@@ -1621,6 +1648,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_tx_power = mwifiex_cfg80211_set_tx_power,
        .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
        .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
+       .set_antenna = mwifiex_cfg80211_set_antenna,
 };
 
 /*
@@ -1687,6 +1715,11 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
        wiphy_apply_custom_regulatory(wdev->wiphy,
                                      &mwifiex_world_regdom_custom);
 
+       wdev->wiphy->available_antennas_tx =
+               BIT(priv->adapter->number_of_antenna) - 1;
+       wdev->wiphy->available_antennas_rx =
+               BIT(priv->adapter->number_of_antenna) - 1;
+
        /* Reserve space for mwifiex specific private data for BSS */
        wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);