wlcore: split 18xx and 12xx scan mechanism
authorEliad Peller <eliad@wizery.com>
Thu, 22 Nov 2012 16:06:15 +0000 (18:06 +0200)
committerLuciano Coelho <coelho@ti.com>
Tue, 27 Nov 2012 08:49:27 +0000 (10:49 +0200)
The scan APIs of 12xx and 18xx are totally different.
Use some common functions as much as possible (e.g.
for setting scan channels), but split scan.c into
chip-specific scan.c files, each implementing its
own scan mechanism.

(in other words - move most of the current wlcore's
scan.c into wl12xx, and implement a similar mechanism
in 18xx, according to the new api)

New wlcore ops are introduced in order to call the
chip-specific scan functions.

The template indices used for each scan (regular/scheduled)
are also different between the chips, so set the correct
indices used for each scan type after identifying the chip.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
17 files changed:
drivers/net/wireless/ti/wl12xx/Makefile
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl12xx/scan.c [new file with mode: 0644]
drivers/net/wireless/ti/wl12xx/scan.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/Makefile
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/scan.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/scan.h [new file with mode: 0644]
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/cmd.h
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/init.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/scan.c
drivers/net/wireless/ti/wlcore/scan.h
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/wlcore.h

index da509aa..8d9afd2 100644 (file)
@@ -1,3 +1,3 @@
-wl12xx-objs    = main.o cmd.o acx.o debugfs.o
+wl12xx-objs    = main.o cmd.o acx.o debugfs.o scan.o
 
 obj-$(CONFIG_WL12XX)           += wl12xx.o
index 6c9fba4..ada7031 100644 (file)
@@ -38,6 +38,7 @@
 #include "reg.h"
 #include "cmd.h"
 #include "acx.h"
+#include "scan.h"
 #include "debugfs.h"
 
 static char *fref_param;
@@ -698,6 +699,11 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                goto out;
        }
 
+       /* common settings */
+       wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY;
+       wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY;
+       wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+       wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
 out:
        return ret;
 }
@@ -1618,6 +1624,11 @@ static struct wlcore_ops wl12xx_ops = {
        .set_rx_csum            = NULL,
        .ap_get_mimo_wide_rate_mask = NULL,
        .debugfs_init           = wl12xx_debugfs_add_files,
+       .scan_start             = wl12xx_scan_start,
+       .scan_stop              = wl12xx_scan_stop,
+       .scan_completed         = wl12xx_scan_completed,
+       .sched_scan_start       = wl12xx_sched_scan_start,
+       .sched_scan_stop        = wl12xx_scan_sched_scan_stop,
        .get_spare_blocks       = wl12xx_get_spare_blocks,
        .set_key                = wl12xx_set_key,
        .pre_pkt_send           = NULL,
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c
new file mode 100644 (file)
index 0000000..a99e876
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/tx.h"
+
+static int wl1271_get_scan_channels(struct wl1271 *wl,
+                                   struct cfg80211_scan_request *req,
+                                   struct basic_scan_channel_params *channels,
+                                   enum ieee80211_band band, bool passive)
+{
+       struct conf_scan_settings *c = &wl->conf.scan;
+       int i, j;
+       u32 flags;
+
+       for (i = 0, j = 0;
+            i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
+            i++) {
+               flags = req->channels[i]->flags;
+
+               if (!test_bit(i, wl->scan.scanned_ch) &&
+                   !(flags & IEEE80211_CHAN_DISABLED) &&
+                   (req->channels[i]->band == band) &&
+                   /*
+                    * In passive scans, we scan all remaining
+                    * channels, even if not marked as such.
+                    * In active scans, we only scan channels not
+                    * marked as passive.
+                    */
+                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
+                       wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+                                    req->channels[i]->band,
+                                    req->channels[i]->center_freq);
+                       wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+                                    req->channels[i]->hw_value,
+                                    req->channels[i]->flags);
+                       wl1271_debug(DEBUG_SCAN,
+                                    "max_antenna_gain %d, max_power %d",
+                                    req->channels[i]->max_antenna_gain,
+                                    req->channels[i]->max_power);
+                       wl1271_debug(DEBUG_SCAN, "beacon_found %d",
+                                    req->channels[i]->beacon_found);
+
+                       if (!passive) {
+                               channels[j].min_duration =
+                                       cpu_to_le32(c->min_dwell_time_active);
+                               channels[j].max_duration =
+                                       cpu_to_le32(c->max_dwell_time_active);
+                       } else {
+                               channels[j].min_duration =
+                                       cpu_to_le32(c->min_dwell_time_passive);
+                               channels[j].max_duration =
+                                       cpu_to_le32(c->max_dwell_time_passive);
+                       }
+                       channels[j].early_termination = 0;
+                       channels[j].tx_power_att = req->channels[i]->max_power;
+                       channels[j].channel = req->channels[i]->hw_value;
+
+                       memset(&channels[j].bssid_lsb, 0xff, 4);
+                       memset(&channels[j].bssid_msb, 0xff, 2);
+
+                       /* Mark the channels we already used */
+                       set_bit(i, wl->scan.scanned_ch);
+
+                       j++;
+               }
+       }
+
+       return j;
+}
+
+#define WL1271_NOTHING_TO_SCAN 1
+
+static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                           enum ieee80211_band band,
+                           bool passive, u32 basic_rate)
+{
+       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+       struct wl1271_cmd_scan *cmd;
+       struct wl1271_cmd_trigger_scan_to *trigger;
+       int ret;
+       u16 scan_options = 0;
+
+       /* skip active scans if we don't have SSIDs */
+       if (!passive && wl->scan.req->n_ssids == 0)
+               return WL1271_NOTHING_TO_SCAN;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+       if (!cmd || !trigger) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (wl->conf.scan.split_scan_timeout)
+               scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
+       if (passive)
+               scan_options |= WL1271_SCAN_OPT_PASSIVE;
+
+       cmd->params.role_id = wlvif->role_id;
+
+       if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       cmd->params.scan_options = cpu_to_le16(scan_options);
+
+       cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
+                                                   cmd->channels,
+                                                   band, passive);
+       if (cmd->params.n_ch == 0) {
+               ret = WL1271_NOTHING_TO_SCAN;
+               goto out;
+       }
+
+       cmd->params.tx_rate = cpu_to_le32(basic_rate);
+       cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
+       cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
+       cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+       if (band == IEEE80211_BAND_2GHZ)
+               cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+       else
+               cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
+
+       if (wl->scan.ssid_len && wl->scan.ssid) {
+               cmd->params.ssid_len = wl->scan.ssid_len;
+               memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
+       }
+
+       memcpy(cmd->addr, vif->addr, ETH_ALEN);
+
+       ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                        cmd->params.role_id, band,
+                                        wl->scan.ssid, wl->scan.ssid_len,
+                                        wl->scan.req->ie,
+                                        wl->scan.req->ie_len, false);
+       if (ret < 0) {
+               wl1271_error("PROBE request template failed");
+               goto out;
+       }
+
+       trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
+       ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+                             sizeof(*trigger), 0);
+       if (ret < 0) {
+               wl1271_error("trigger scan to failed for hw scan");
+               goto out;
+       }
+
+       wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+       ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("SCAN failed");
+               goto out;
+       }
+
+out:
+       kfree(cmd);
+       kfree(trigger);
+       return ret;
+}
+
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       struct wl1271_cmd_header *cmd = NULL;
+       int ret = 0;
+
+       if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
+               return -EINVAL;
+
+       wl1271_debug(DEBUG_CMD, "cmd scan stop");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
+                             sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("cmd stop_scan failed");
+               goto out;
+       }
+out:
+       kfree(cmd);
+       return ret;
+}
+
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       int ret = 0;
+       enum ieee80211_band band;
+       u32 rate, mask;
+
+       switch (wl->scan.state) {
+       case WL1271_SCAN_STATE_IDLE:
+               break;
+
+       case WL1271_SCAN_STATE_2GHZ_ACTIVE:
+               band = IEEE80211_BAND_2GHZ;
+               mask = wlvif->bitrate_masks[band];
+               if (wl->scan.req->no_cck) {
+                       mask &= ~CONF_TX_CCK_RATES;
+                       if (!mask)
+                               mask = CONF_TX_RATE_MASK_BASIC_P2P;
+               }
+               rate = wl1271_tx_min_rate_get(wl, mask);
+               ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+               if (ret == WL1271_NOTHING_TO_SCAN) {
+                       wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
+                       wl1271_scan_stm(wl, wlvif);
+               }
+
+               break;
+
+       case WL1271_SCAN_STATE_2GHZ_PASSIVE:
+               band = IEEE80211_BAND_2GHZ;
+               mask = wlvif->bitrate_masks[band];
+               if (wl->scan.req->no_cck) {
+                       mask &= ~CONF_TX_CCK_RATES;
+                       if (!mask)
+                               mask = CONF_TX_RATE_MASK_BASIC_P2P;
+               }
+               rate = wl1271_tx_min_rate_get(wl, mask);
+               ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+               if (ret == WL1271_NOTHING_TO_SCAN) {
+                       if (wl->enable_11a)
+                               wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
+                       else
+                               wl->scan.state = WL1271_SCAN_STATE_DONE;
+                       wl1271_scan_stm(wl, wlvif);
+               }
+
+               break;
+
+       case WL1271_SCAN_STATE_5GHZ_ACTIVE:
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+               if (ret == WL1271_NOTHING_TO_SCAN) {
+                       wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
+                       wl1271_scan_stm(wl, wlvif);
+               }
+
+               break;
+
+       case WL1271_SCAN_STATE_5GHZ_PASSIVE:
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+               if (ret == WL1271_NOTHING_TO_SCAN) {
+                       wl->scan.state = WL1271_SCAN_STATE_DONE;
+                       wl1271_scan_stm(wl, wlvif);
+               }
+
+               break;
+
+       case WL1271_SCAN_STATE_DONE:
+               wl->scan.failed = false;
+               cancel_delayed_work(&wl->scan_complete_work);
+               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                            msecs_to_jiffies(0));
+               break;
+
+       default:
+               wl1271_error("invalid scan state");
+               break;
+       }
+
+       if (ret < 0) {
+               cancel_delayed_work(&wl->scan_complete_work);
+               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                            msecs_to_jiffies(0));
+       }
+}
+
+static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
+                                  struct wlcore_scan_channels *cmd_channels)
+{
+       memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+       memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+       cmd->dfs = cmd_channels->dfs;
+       cmd->n_pactive_ch = cmd_channels->passive_active;
+
+       memcpy(cmd->channels_2, cmd_channels->channels_2,
+              sizeof(cmd->channels_2));
+       memcpy(cmd->channels_5, cmd_channels->channels_5,
+              sizeof(cmd->channels_2));
+       /* channels_4 are not supported, so no need to copy them */
+}
+
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+                                 struct wl12xx_vif *wlvif,
+                                 struct cfg80211_sched_scan_request *req,
+                                 struct ieee80211_sched_scan_ies *ies)
+{
+       struct wl1271_cmd_sched_scan_config *cfg = NULL;
+       struct wlcore_scan_channels *cfg_channels = NULL;
+       struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+       int i, ret;
+       bool force_passive = !req->n_ssids;
+
+       wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+       cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       cfg->role_id = wlvif->role_id;
+       cfg->rssi_threshold = c->rssi_threshold;
+       cfg->snr_threshold  = c->snr_threshold;
+       cfg->n_probe_reqs = c->num_probe_reqs;
+       /* cycles set to 0 it means infinite (until manually stopped) */
+       cfg->cycles = 0;
+       /* report APs when at least 1 is found */
+       cfg->report_after = 1;
+       /* don't stop scanning automatically when something is found */
+       cfg->terminate = 0;
+       cfg->tag = WL1271_SCAN_DEFAULT_TAG;
+       /* don't filter on BSS type */
+       cfg->bss_type = SCAN_BSS_TYPE_ANY;
+       /* currently NL80211 supports only a single interval */
+       for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
+               cfg->intervals[i] = cpu_to_le32(req->interval);
+
+       cfg->ssid_len = 0;
+       ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+       if (ret < 0)
+               goto out;
+
+       cfg->filter_type = ret;
+
+       wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
+
+       cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL);
+       if (!cfg_channels) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels,
+                                        req->n_channels, req->n_ssids)) {
+               wl1271_error("scan channel list is empty");
+               ret = -EINVAL;
+               goto out;
+       }
+       wl12xx_adjust_channels(cfg, cfg_channels);
+
+       if (!force_passive && cfg->active[0]) {
+               u8 band = IEEE80211_BAND_2GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                wlvif->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                ies->ie[band],
+                                                ies->len[band], true);
+               if (ret < 0) {
+                       wl1271_error("2.4GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       if (!force_passive && cfg->active[1]) {
+               u8 band = IEEE80211_BAND_5GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                wlvif->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                ies->ie[band],
+                                                ies->len[band], true);
+               if (ret < 0) {
+                       wl1271_error("5GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
+
+       ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
+                             sizeof(*cfg), 0);
+       if (ret < 0) {
+               wl1271_error("SCAN configuration failed");
+               goto out;
+       }
+out:
+       kfree(cfg_channels);
+       kfree(cfg);
+       return ret;
+}
+
+int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       struct wl1271_cmd_sched_scan_start *start;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
+
+       if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+               return -EOPNOTSUPP;
+
+       if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
+           test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
+               return -EBUSY;
+
+       start = kzalloc(sizeof(*start), GFP_KERNEL);
+       if (!start)
+               return -ENOMEM;
+
+       start->role_id = wlvif->role_id;
+       start->tag = WL1271_SCAN_DEFAULT_TAG;
+
+       ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
+                             sizeof(*start), 0);
+       if (ret < 0) {
+               wl1271_error("failed to send scan start command");
+               goto out_free;
+       }
+
+out_free:
+       kfree(start);
+       return ret;
+}
+
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif  *wlvif,
+                           struct cfg80211_sched_scan_request *req,
+                           struct ieee80211_sched_scan_ies *ies)
+{
+       int ret;
+
+       ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
+       if (ret < 0)
+               return ret;
+
+       return wl1271_scan_sched_scan_start(wl, wlvif);
+}
+
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
+{
+       struct wl1271_cmd_sched_scan_stop *stop;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+       /* FIXME: what to do if alloc'ing to stop fails? */
+       stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+       if (!stop) {
+               wl1271_error("failed to alloc memory to send sched scan stop");
+               return;
+       }
+
+       stop->role_id = wlvif->role_id;
+       stop->tag = WL1271_SCAN_DEFAULT_TAG;
+
+       ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
+                             sizeof(*stop), 0);
+       if (ret < 0) {
+               wl1271_error("failed to send sched scan stop command");
+               goto out_free;
+       }
+
+out_free:
+       kfree(stop);
+}
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                     struct cfg80211_scan_request *req)
+{
+       wl1271_scan_stm(wl, wlvif);
+       return 0;
+}
+
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       wl1271_scan_stm(wl, wlvif);
+}
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h
new file mode 100644 (file)
index 0000000..bd075de
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_SCAN_H__
+#define __WL12XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+struct basic_scan_params {
+       /* Scan option flags (WL1271_SCAN_OPT_*) */
+       __le16 scan_options;
+       u8 role_id;
+       /* Number of scan channels in the list (maximum 30) */
+       u8 n_ch;
+       /* This field indicates the number of probe requests to send
+          per channel for an active scan */
+       u8 n_probe_reqs;
+       u8 tid_trigger;
+       u8 ssid_len;
+       u8 use_ssid_list;
+
+       /* Rate bit field for sending the probes */
+       __le32 tx_rate;
+
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       /* Band to scan */
+       u8 band;
+
+       u8 scan_tag;
+       u8 padding2[2];
+} __packed;
+
+struct basic_scan_channel_params {
+       /* Duration in TU to wait for frames on a channel for active scan */
+       __le32 min_duration;
+       __le32 max_duration;
+       __le32 bssid_lsb;
+       __le16 bssid_msb;
+       u8 early_termination;
+       u8 tx_power_att;
+       u8 channel;
+       /* FW internal use only! */
+       u8 dfs_candidate;
+       u8 activity_detected;
+       u8 pad;
+} __packed;
+
+struct wl1271_cmd_scan {
+       struct wl1271_cmd_header header;
+
+       struct basic_scan_params params;
+       struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+       /* src mac address */
+       u8 addr[ETH_ALEN];
+       u8 padding[2];
+} __packed;
+
+struct wl1271_cmd_sched_scan_config {
+       struct wl1271_cmd_header header;
+
+       __le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
+
+       s8 rssi_threshold; /* for filtering (in dBm) */
+       s8 snr_threshold;  /* for filtering (in dB) */
+
+       u8 cycles;       /* maximum number of scan cycles */
+       u8 report_after; /* report when this number of results are received */
+       u8 terminate;    /* stop scanning after reporting */
+
+       u8 tag;
+       u8 bss_type; /* for filtering */
+       u8 filter_type;
+
+       u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+       u8 n_probe_reqs; /* Number of probes requests per channel */
+
+       u8 passive[SCAN_MAX_BANDS];
+       u8 active[SCAN_MAX_BANDS];
+
+       u8 dfs;
+
+       u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
+                           channels in BG band */
+       u8 role_id;
+       u8 padding[1];
+       struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+       struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+       struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+} __packed;
+
+struct wl1271_cmd_sched_scan_start {
+       struct wl1271_cmd_header header;
+
+       u8 tag;
+       u8 role_id;
+       u8 padding[2];
+} __packed;
+
+struct wl1271_cmd_sched_scan_stop {
+       struct wl1271_cmd_header header;
+
+       u8 tag;
+       u8 role_id;
+       u8 padding[2];
+} __packed;
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                     struct cfg80211_scan_request *req);
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif  *wlvif,
+                           struct cfg80211_sched_scan_request *req,
+                           struct ieee80211_sched_scan_ies *ies);
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
+#endif
index 67c0987..f742249 100644 (file)
@@ -1,3 +1,3 @@
-wl18xx-objs    = main.o acx.o tx.o io.o debugfs.o
+wl18xx-objs    = main.o acx.o tx.o io.o debugfs.o scan.o
 
 obj-$(CONFIG_WL18XX)           += wl18xx.o
index 8ba1c93..97c23c8 100644 (file)
@@ -38,6 +38,7 @@
 #include "tx.h"
 #include "wl18xx.h"
 #include "io.h"
+#include "scan.h"
 #include "debugfs.h"
 
 #define WL18XX_RX_CHECKSUM_MASK      0x40
@@ -612,7 +613,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
                              WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
                              WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
                              WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
-                             WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+                             WLCORE_QUIRK_TX_PAD_LAST_FRAME |
+                             WLCORE_QUIRK_DUAL_PROBE_TMPL;
 
                wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
                                      WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER,
@@ -630,6 +632,10 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
                goto out;
        }
 
+       wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+       wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+       wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
+       wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
 out:
        return ret;
 }
@@ -1320,6 +1326,11 @@ static struct wlcore_ops wl18xx_ops = {
        .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
        .get_mac        = wl18xx_get_mac,
        .debugfs_init   = wl18xx_debugfs_add_files,
+       .scan_start     = wl18xx_scan_start,
+       .scan_stop      = wl18xx_scan_stop,
+       .scan_completed = wl18xx_scan_completed,
+       .sched_scan_start       = wl18xx_sched_scan_start,
+       .sched_scan_stop        = wl18xx_scan_sched_scan_stop,
        .handle_static_data     = wl18xx_handle_static_data,
        .get_spare_blocks = wl18xx_get_spare_blocks,
        .set_key        = wl18xx_set_key,
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
new file mode 100644 (file)
index 0000000..f31d0d4
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+
+static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
+                                  struct wlcore_scan_channels *cmd_channels)
+{
+       memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+       memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+       cmd->dfs = cmd_channels->dfs;
+       cmd->passive_active = cmd_channels->passive_active;
+
+       memcpy(cmd->channels_2, cmd_channels->channels_2,
+              sizeof(cmd->channels_2));
+       memcpy(cmd->channels_5, cmd_channels->channels_5,
+              sizeof(cmd->channels_2));
+       /* channels_4 are not supported, so no need to copy them */
+}
+
+static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                           struct cfg80211_scan_request *req)
+{
+       struct wl18xx_cmd_scan_params *cmd;
+       struct wlcore_scan_channels *cmd_channels = NULL;
+       int ret;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cmd->role_id = wlvif->role_id;
+
+       if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       cmd->scan_type = SCAN_TYPE_SEARCH;
+       cmd->rssi_threshold = -127;
+       cmd->snr_threshold = 0;
+
+       cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+       cmd->ssid_from_list = 0;
+       cmd->filter = 0;
+       cmd->add_broadcast = 0;
+
+       cmd->urgency = 0;
+       cmd->protect = 0;
+
+       cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
+       cmd->terminate_after = 0;
+
+       /* configure channels */
+       WARN_ON(req->n_ssids > 1);
+
+       cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+       if (!cmd_channels) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+                                   req->n_channels, req->n_ssids);
+       wl18xx_adjust_channels(cmd, cmd_channels);
+
+       /*
+        * all the cycles params (except total cycles) should
+        * remain 0 for normal scan
+        */
+       cmd->total_cycles = 1;
+
+       if (req->no_cck)
+               cmd->rate = WL18XX_SCAN_RATE_6;
+
+       cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+       if (req->n_ssids) {
+               cmd->ssid_len = req->ssids[0].ssid_len;
+               memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
+       }
+
+       /* TODO: per-band ies? */
+       if (cmd->active[0]) {
+               u8 band = IEEE80211_BAND_2GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                cmd->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                req->ie,
+                                                req->ie_len,
+                                                false);
+               if (ret < 0) {
+                       wl1271_error("2.4GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       if (cmd->active[1]) {
+               u8 band = IEEE80211_BAND_5GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                cmd->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                req->ie,
+                                                req->ie_len,
+                                                false);
+               if (ret < 0) {
+                       wl1271_error("5GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+       ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("SCAN failed");
+               goto out;
+       }
+
+out:
+       kfree(cmd_channels);
+       kfree(cmd);
+       return ret;
+}
+
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       wl->scan.failed = false;
+       cancel_delayed_work(&wl->scan_complete_work);
+       ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                    msecs_to_jiffies(0));
+}
+
+static
+int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
+                                 struct wl12xx_vif *wlvif,
+                                 struct cfg80211_sched_scan_request *req,
+                                 struct ieee80211_sched_scan_ies *ies)
+{
+       struct wl18xx_cmd_scan_params *cmd;
+       struct wlcore_scan_channels *cmd_channels = NULL;
+       struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+       int ret;
+       int filter_type;
+
+       wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+       filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+       if (filter_type < 0)
+               return filter_type;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       cmd->role_id = wlvif->role_id;
+
+       if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       cmd->scan_type = SCAN_TYPE_PERIODIC;
+       cmd->rssi_threshold = c->rssi_threshold;
+       cmd->snr_threshold = c->snr_threshold;
+
+       /* don't filter on BSS type */
+       cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+       cmd->ssid_from_list = 1;
+       if (filter_type == SCAN_SSID_FILTER_LIST)
+               cmd->filter = 1;
+       cmd->add_broadcast = 0;
+
+       cmd->urgency = 0;
+       cmd->protect = 0;
+
+       cmd->n_probe_reqs = c->num_probe_reqs;
+       /* don't stop scanning automatically when something is found */
+       cmd->terminate_after = 0;
+
+       cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+       if (!cmd_channels) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* configure channels */
+       wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+                                   req->n_channels, req->n_ssids);
+       wl18xx_adjust_channels(cmd, cmd_channels);
+
+       cmd->short_cycles_sec = 0;
+       cmd->long_cycles_sec = cpu_to_le16(req->interval);
+       cmd->short_cycles_count = 0;
+
+       cmd->total_cycles = 0;
+
+       cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+       if (cmd->active[0]) {
+               u8 band = IEEE80211_BAND_2GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                cmd->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                ies->ie[band],
+                                                ies->len[band],
+                                                true);
+               if (ret < 0) {
+                       wl1271_error("2.4GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       if (cmd->active[1]) {
+               u8 band = IEEE80211_BAND_5GHZ;
+               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+                                                cmd->role_id, band,
+                                                req->ssids[0].ssid,
+                                                req->ssids[0].ssid_len,
+                                                ies->ie[band],
+                                                ies->len[band],
+                                                true);
+               if (ret < 0) {
+                       wl1271_error("5GHz PROBE request template failed");
+                       goto out;
+               }
+       }
+
+       wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+       ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("SCAN failed");
+               goto out;
+       }
+
+out:
+       kfree(cmd_channels);
+       kfree(cmd);
+       return ret;
+}
+
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                           struct cfg80211_sched_scan_request *req,
+                           struct ieee80211_sched_scan_ies *ies)
+{
+       return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
+}
+
+static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                              u8 scan_type)
+{
+       struct wl18xx_cmd_scan_stop *stop;
+       int ret;
+
+       wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+       stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+       if (!stop) {
+               wl1271_error("failed to alloc memory to send sched scan stop");
+               return -ENOMEM;
+       }
+
+       stop->role_id = wlvif->role_id;
+       stop->scan_type = scan_type;
+
+       ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
+       if (ret < 0) {
+               wl1271_error("failed to send sched scan stop command");
+               goto out_free;
+       }
+
+out_free:
+       kfree(stop);
+       return ret;
+}
+
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
+}
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                     struct cfg80211_scan_request *req)
+{
+       return wl18xx_scan_send(wl, wlvif, req);
+}
+
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+       return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
+}
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h
new file mode 100644 (file)
index 0000000..404baf1
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_SCAN_H__
+#define __WL18XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+struct tracking_ch_params {
+       struct conn_scan_ch_params channel;
+
+       __le32 bssid_lsb;
+       __le16 bssid_msb;
+
+       u8 padding[2];
+} __packed;
+
+enum
+{
+       SCAN_TYPE_SEARCH        = 0,
+       SCAN_TYPE_PERIODIC      = 1,
+       SCAN_TYPE_TRACKING      = 2,
+};
+
+/* probe request rate */
+enum
+{
+       WL18XX_SCAN_RATE_1      = 0,
+       WL18XX_SCAN_RATE_5_5    = 1,
+       WL18XX_SCAN_RATE_6      = 2,
+};
+
+struct wl18xx_cmd_scan_params {
+       struct wl1271_cmd_header header;
+
+       u8 role_id;
+       u8 scan_type;
+
+       s8 rssi_threshold; /* for filtering (in dBm) */
+       s8 snr_threshold;  /* for filtering (in dB) */
+
+       u8 bss_type;       /* for filtering */
+       u8 ssid_from_list; /* use ssid from configured ssid list */
+       u8 filter;         /* forward only results with matching ssids */
+
+       /*
+        * add broadcast ssid in addition to the configured ssids.
+        * the driver should add dummy entry for it (?).
+        */
+       u8 add_broadcast;
+
+       u8 urgency;
+       u8 protect;      /* ??? */
+       u8 n_probe_reqs;    /* Number of probes requests per channel */
+       u8 terminate_after; /* early terminate scan operation */
+
+       u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+       u8 active[SCAN_MAX_BANDS];  /* number of active scan channels */
+       u8 dfs;            /* number of dfs channels in 5ghz */
+       u8 passive_active; /* number of passive before active channels 2.4ghz */
+
+       __le16 short_cycles_sec;
+       __le16 long_cycles_sec;
+       u8 short_cycles_count;
+       u8 total_cycles; /* 0 - infinite */
+       u8 rate;
+       u8 padding[1];
+
+       union {
+               struct {
+                       struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+                       struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+                       struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+               };
+               struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS];
+       } ;
+
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
+       u8 tag;
+       u8 padding1[2];
+} __packed;
+
+struct wl18xx_cmd_scan_stop {
+       struct wl1271_cmd_header header;
+
+       u8 role_id;
+       u8 scan_type;
+       u8 padding[2];
+} __packed;
+
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                     struct cfg80211_scan_request *req);
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                           struct cfg80211_sched_scan_request *req,
+                           struct ieee80211_sched_scan_ies *ies);
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+#endif
index 04ba86d..c8c7766 100644 (file)
@@ -131,6 +131,7 @@ fail:
        wl12xx_queue_recovery_work(wl);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_cmd_send);
 
 /*
  * Poll the mailbox event field until any of the bits in the mask is set or a
@@ -1049,8 +1050,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        struct sk_buff *skb;
        int ret;
        u32 rate;
-       u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
-       u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+       u16 template_id_2_4 = wl->scan_templ_id_2_4;
+       u16 template_id_5 = wl->scan_templ_id_5;
 
        skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
                                     ie, ie_len);
@@ -1061,10 +1062,10 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
 
-       if (!sched_scan &&
+       if (sched_scan &&
            (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
-               template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4;
-               template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5;
+               template_id_2_4 = wl->sched_scan_templ_id_2_4;
+               template_id_5 = wl->sched_scan_templ_id_5;
        }
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
@@ -1081,6 +1082,7 @@ out:
        dev_kfree_skb(skb);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl12xx_cmd_build_probe_req);
 
 struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
                                              struct wl12xx_vif *wlvif,
index d021305..9e9062f 100644 (file)
@@ -172,8 +172,8 @@ enum cmd_templ {
        CMD_TEMPL_PS_POLL,
        CMD_TEMPL_KLV,
        CMD_TEMPL_DISCONNECT,
-       CMD_TEMPL_APP_PROBE_REQ_2_4,
-       CMD_TEMPL_APP_PROBE_REQ_5,
+       CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY,
+       CMD_TEMPL_APP_PROBE_REQ_5_LEGACY,
        CMD_TEMPL_BAR,           /* for firmware internal use only */
        CMD_TEMPL_CTS,           /*
                                  * For CTS-to-self (FastCTS) mechanism
@@ -184,6 +184,8 @@ enum cmd_templ {
        CMD_TEMPL_DEAUTH_AP,
        CMD_TEMPL_TEMPORARY,
        CMD_TEMPL_LINK_MEASUREMENT_REPORT,
+       CMD_TEMPL_PROBE_REQ_2_4_PERIODIC,
+       CMD_TEMPL_PROBE_REQ_5_PERIODIC,
 
        CMD_TEMPL_MAX = 0xff
 };
index cf45aaf..d9353da 100644 (file)
@@ -117,7 +117,9 @@ static int wl1271_event_process(struct wl1271 *wl)
                wl1271_debug(DEBUG_EVENT, "status: 0x%x",
                             mbox->scheduled_scan_status);
 
-               wl1271_scan_stm(wl, wl->scan_vif);
+               if (wl->scan_vif)
+                       wl->ops->scan_completed(wl,
+                                       wl12xx_vif_to_data(wl->scan_vif));
        }
 
        if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
index 84641b3..06e1bf9 100644 (file)
@@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl)
 
        /* send empty templates for fw memory reservation */
        ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-                                     CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+                                     wl->scan_templ_id_2_4, NULL,
                                      WL1271_CMD_TEMPL_MAX_SIZE,
                                      0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-                                     CMD_TEMPL_CFG_PROBE_REQ_5,
+                                     wl->scan_templ_id_5,
                                      NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
                                      WL1271_RATE_AUTOMATIC);
        if (ret < 0)
@@ -56,14 +56,16 @@ int wl1271_init_templates_config(struct wl1271 *wl)
 
        if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
                ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-                                             CMD_TEMPL_APP_PROBE_REQ_2_4, NULL,
+                                             wl->sched_scan_templ_id_2_4,
+                                             NULL,
                                              WL1271_CMD_TEMPL_MAX_SIZE,
                                              0, WL1271_RATE_AUTOMATIC);
                if (ret < 0)
                        return ret;
 
                ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-                                             CMD_TEMPL_APP_PROBE_REQ_5, NULL,
+                                             wl->sched_scan_templ_id_5,
+                                             NULL,
                                              WL1271_CMD_TEMPL_MAX_SIZE,
                                              0, WL1271_RATE_AUTOMATIC);
                if (ret < 0)
index 111b84f..0f7a933 100644 (file)
@@ -3252,7 +3252,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
                goto out_sleep;
        }
 
-       ret = wl1271_scan(hw->priv, vif, ssid, len, req);
+       ret = wlcore_scan(hw->priv, vif, ssid, len, req);
 out_sleep:
        wl1271_ps_elp_sleep(wl);
 out:
@@ -3265,6 +3265,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
@@ -3282,7 +3283,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
                goto out;
 
        if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
-               ret = wl1271_scan_stop(wl);
+               ret = wl->ops->scan_stop(wl, wlvif);
                if (ret < 0)
                        goto out_sleep;
        }
@@ -3329,11 +3330,7 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
-       if (ret < 0)
-               goto out_sleep;
-
-       ret = wl1271_scan_sched_scan_start(wl, wlvif);
+       ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
        if (ret < 0)
                goto out_sleep;
 
@@ -3364,7 +3361,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       wl1271_scan_sched_scan_stop(wl, wlvif);
+       wl->ops->sched_scan_stop(wl, wlvif);
 
        wl1271_ps_elp_sleep(wl);
 out:
@@ -3821,7 +3818,7 @@ static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        /* we only support sched_scan while not connected */
        if (wl->sched_scanning)
-               wl1271_scan_sched_scan_stop(wl, wlvif);
+               wl->ops->sched_scan_stop(wl, wlvif);
 
        ret = wl1271_acx_sta_rate_policies(wl, wlvif);
        if (ret < 0)
index 22dd7e9..9eab64d 100644 (file)
@@ -89,319 +89,6 @@ out:
 
 }
 
-
-static int wl1271_get_scan_channels(struct wl1271 *wl,
-                                   struct cfg80211_scan_request *req,
-                                   struct basic_scan_channel_params *channels,
-                                   enum ieee80211_band band, bool passive)
-{
-       struct conf_scan_settings *c = &wl->conf.scan;
-       int i, j;
-       u32 flags;
-
-       for (i = 0, j = 0;
-            i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
-            i++) {
-               flags = req->channels[i]->flags;
-
-               if (!test_bit(i, wl->scan.scanned_ch) &&
-                   !(flags & IEEE80211_CHAN_DISABLED) &&
-                   (req->channels[i]->band == band) &&
-                   /*
-                    * In passive scans, we scan all remaining
-                    * channels, even if not marked as such.
-                    * In active scans, we only scan channels not
-                    * marked as passive.
-                    */
-                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
-                       wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
-                                    req->channels[i]->band,
-                                    req->channels[i]->center_freq);
-                       wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
-                                    req->channels[i]->hw_value,
-                                    req->channels[i]->flags);
-                       wl1271_debug(DEBUG_SCAN,
-                                    "max_antenna_gain %d, max_power %d",
-                                    req->channels[i]->max_antenna_gain,
-                                    req->channels[i]->max_power);
-                       wl1271_debug(DEBUG_SCAN, "beacon_found %d",
-                                    req->channels[i]->beacon_found);
-
-                       if (!passive) {
-                               channels[j].min_duration =
-                                       cpu_to_le32(c->min_dwell_time_active);
-                               channels[j].max_duration =
-                                       cpu_to_le32(c->max_dwell_time_active);
-                       } else {
-                               channels[j].min_duration =
-                                       cpu_to_le32(c->min_dwell_time_passive);
-                               channels[j].max_duration =
-                                       cpu_to_le32(c->max_dwell_time_passive);
-                       }
-                       channels[j].early_termination = 0;
-                       channels[j].tx_power_att = req->channels[i]->max_power;
-                       channels[j].channel = req->channels[i]->hw_value;
-
-                       memset(&channels[j].bssid_lsb, 0xff, 4);
-                       memset(&channels[j].bssid_msb, 0xff, 2);
-
-                       /* Mark the channels we already used */
-                       set_bit(i, wl->scan.scanned_ch);
-
-                       j++;
-               }
-       }
-
-       return j;
-}
-
-#define WL1271_NOTHING_TO_SCAN 1
-
-static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
-                           enum ieee80211_band band,
-                           bool passive, u32 basic_rate)
-{
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-       struct wl1271_cmd_scan *cmd;
-       struct wl1271_cmd_trigger_scan_to *trigger;
-       int ret;
-       u16 scan_options = 0;
-
-       /* skip active scans if we don't have SSIDs */
-       if (!passive && wl->scan.req->n_ssids == 0)
-               return WL1271_NOTHING_TO_SCAN;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
-       if (!cmd || !trigger) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       if (wl->conf.scan.split_scan_timeout)
-               scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
-
-       if (passive)
-               scan_options |= WL1271_SCAN_OPT_PASSIVE;
-
-       cmd->params.role_id = wlvif->role_id;
-
-       if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       cmd->params.scan_options = cpu_to_le16(scan_options);
-
-       cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
-                                                   cmd->channels,
-                                                   band, passive);
-       if (cmd->params.n_ch == 0) {
-               ret = WL1271_NOTHING_TO_SCAN;
-               goto out;
-       }
-
-       cmd->params.tx_rate = cpu_to_le32(basic_rate);
-       cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
-       cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
-       cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
-
-       if (band == IEEE80211_BAND_2GHZ)
-               cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
-       else
-               cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
-
-       if (wl->scan.ssid_len && wl->scan.ssid) {
-               cmd->params.ssid_len = wl->scan.ssid_len;
-               memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
-       }
-
-       memcpy(cmd->addr, vif->addr, ETH_ALEN);
-
-       ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-                                        cmd->params.role_id, band,
-                                        wl->scan.ssid, wl->scan.ssid_len,
-                                        wl->scan.req->ie,
-                                        wl->scan.req->ie_len, false);
-       if (ret < 0) {
-               wl1271_error("PROBE request template failed");
-               goto out;
-       }
-
-       trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
-       ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
-                             sizeof(*trigger), 0);
-       if (ret < 0) {
-               wl1271_error("trigger scan to failed for hw scan");
-               goto out;
-       }
-
-       wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
-
-       ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
-       if (ret < 0) {
-               wl1271_error("SCAN failed");
-               goto out;
-       }
-
-out:
-       kfree(cmd);
-       kfree(trigger);
-       return ret;
-}
-
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif)
-{
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-       int ret = 0;
-       enum ieee80211_band band;
-       u32 rate, mask;
-
-       switch (wl->scan.state) {
-       case WL1271_SCAN_STATE_IDLE:
-               break;
-
-       case WL1271_SCAN_STATE_2GHZ_ACTIVE:
-               band = IEEE80211_BAND_2GHZ;
-               mask = wlvif->bitrate_masks[band];
-               if (wl->scan.req->no_cck) {
-                       mask &= ~CONF_TX_CCK_RATES;
-                       if (!mask)
-                               mask = CONF_TX_RATE_MASK_BASIC_P2P;
-               }
-               rate = wl1271_tx_min_rate_get(wl, mask);
-               ret = wl1271_scan_send(wl, vif, band, false, rate);
-               if (ret == WL1271_NOTHING_TO_SCAN) {
-                       wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
-                       wl1271_scan_stm(wl, vif);
-               }
-
-               break;
-
-       case WL1271_SCAN_STATE_2GHZ_PASSIVE:
-               band = IEEE80211_BAND_2GHZ;
-               mask = wlvif->bitrate_masks[band];
-               if (wl->scan.req->no_cck) {
-                       mask &= ~CONF_TX_CCK_RATES;
-                       if (!mask)
-                               mask = CONF_TX_RATE_MASK_BASIC_P2P;
-               }
-               rate = wl1271_tx_min_rate_get(wl, mask);
-               ret = wl1271_scan_send(wl, vif, band, true, rate);
-               if (ret == WL1271_NOTHING_TO_SCAN) {
-                       if (wl->enable_11a)
-                               wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
-                       else
-                               wl->scan.state = WL1271_SCAN_STATE_DONE;
-                       wl1271_scan_stm(wl, vif);
-               }
-
-               break;
-
-       case WL1271_SCAN_STATE_5GHZ_ACTIVE:
-               band = IEEE80211_BAND_5GHZ;
-               rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
-               ret = wl1271_scan_send(wl, vif, band, false, rate);
-               if (ret == WL1271_NOTHING_TO_SCAN) {
-                       wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
-                       wl1271_scan_stm(wl, vif);
-               }
-
-               break;
-
-       case WL1271_SCAN_STATE_5GHZ_PASSIVE:
-               band = IEEE80211_BAND_5GHZ;
-               rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
-               ret = wl1271_scan_send(wl, vif, band, true, rate);
-               if (ret == WL1271_NOTHING_TO_SCAN) {
-                       wl->scan.state = WL1271_SCAN_STATE_DONE;
-                       wl1271_scan_stm(wl, vif);
-               }
-
-               break;
-
-       case WL1271_SCAN_STATE_DONE:
-               wl->scan.failed = false;
-               cancel_delayed_work(&wl->scan_complete_work);
-               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-                                            msecs_to_jiffies(0));
-               break;
-
-       default:
-               wl1271_error("invalid scan state");
-               break;
-       }
-
-       if (ret < 0) {
-               cancel_delayed_work(&wl->scan_complete_work);
-               ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-                                            msecs_to_jiffies(0));
-       }
-}
-
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
-               const u8 *ssid, size_t ssid_len,
-               struct cfg80211_scan_request *req)
-{
-       /*
-        * cfg80211 should guarantee that we don't get more channels
-        * than what we have registered.
-        */
-       BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
-
-       if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
-               return -EBUSY;
-
-       wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
-
-       if (ssid_len && ssid) {
-               wl->scan.ssid_len = ssid_len;
-               memcpy(wl->scan.ssid, ssid, ssid_len);
-       } else {
-               wl->scan.ssid_len = 0;
-       }
-
-       wl->scan_vif = vif;
-       wl->scan.req = req;
-       memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
-
-       /* we assume failure so that timeout scenarios are handled correctly */
-       wl->scan.failed = true;
-       ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-                                    msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
-
-       wl1271_scan_stm(wl, vif);
-
-       return 0;
-}
-
-int wl1271_scan_stop(struct wl1271 *wl)
-{
-       struct wl1271_cmd_header *cmd = NULL;
-       int ret = 0;
-
-       if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
-               return -EINVAL;
-
-       wl1271_debug(DEBUG_CMD, "cmd scan stop");
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
-                             sizeof(*cmd), 0);
-       if (ret < 0) {
-               wl1271_error("cmd stop_scan failed");
-               goto out;
-       }
-out:
-       kfree(cmd);
-       return ret;
-}
-
 static int
 wlcore_scan_get_channels(struct wl1271 *wl,
                         struct ieee80211_channel *req_channels[],
@@ -503,9 +190,9 @@ wlcore_scan_get_channels(struct wl1271 *wl,
        return j - start;
 }
 
-static bool
+bool
 wlcore_set_scan_chan_params(struct wl1271 *wl,
-                           struct wl1271_cmd_sched_scan_config *cfg,
+                           struct wlcore_scan_channels *cfg,
                            struct ieee80211_channel *channels[],
                            u32 n_channels,
                            u32 n_ssids)
@@ -570,7 +257,7 @@ wlcore_set_scan_chan_params(struct wl1271 *wl,
        cfg->passive[2] = 0;
        cfg->active[2] = 0;
 
-       cfg->n_pactive_ch = n_pactive_ch;
+       cfg->passive_active = n_pactive_ch;
 
        wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
                     cfg->active[0], cfg->passive[0]);
@@ -582,10 +269,48 @@ wlcore_set_scan_chan_params(struct wl1271 *wl,
                cfg->passive[1] || cfg->active[1] || cfg->dfs ||
                cfg->passive[2] || cfg->active[2];
 }
+EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params);
 
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+               const u8 *ssid, size_t ssid_len,
+               struct cfg80211_scan_request *req)
+{
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+
+       /*
+        * cfg80211 should guarantee that we don't get more channels
+        * than what we have registered.
+        */
+       BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
+
+       if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
+               return -EBUSY;
+
+       wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
+
+       if (ssid_len && ssid) {
+               wl->scan.ssid_len = ssid_len;
+               memcpy(wl->scan.ssid, ssid, ssid_len);
+       } else {
+               wl->scan.ssid_len = 0;
+       }
+
+       wl->scan_vif = vif;
+       wl->scan.req = req;
+       memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
+
+       /* we assume failure so that timeout scenarios are handled correctly */
+       wl->scan.failed = true;
+       ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+                                    msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
+
+       wl->ops->scan_start(wl, wlvif, req);
+
+       return 0;
+}
 /* Returns the scan type to be used or a negative value on error */
-static int
-wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
                                 struct wl12xx_vif *wlvif,
                                 struct cfg80211_sched_scan_request *req)
 {
@@ -688,129 +413,7 @@ out:
                return ret;
        return type;
 }
-
-int wl1271_scan_sched_scan_config(struct wl1271 *wl,
-                                 struct wl12xx_vif *wlvif,
-                                 struct cfg80211_sched_scan_request *req,
-                                 struct ieee80211_sched_scan_ies *ies)
-{
-       struct wl1271_cmd_sched_scan_config *cfg = NULL;
-       struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
-       int i, ret;
-       bool force_passive = !req->n_ssids;
-
-       wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
-
-       cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
-       if (!cfg)
-               return -ENOMEM;
-
-       cfg->role_id = wlvif->role_id;
-       cfg->rssi_threshold = c->rssi_threshold;
-       cfg->snr_threshold  = c->snr_threshold;
-       cfg->n_probe_reqs = c->num_probe_reqs;
-       /* cycles set to 0 it means infinite (until manually stopped) */
-       cfg->cycles = 0;
-       /* report APs when at least 1 is found */
-       cfg->report_after = 1;
-       /* don't stop scanning automatically when something is found */
-       cfg->terminate = 0;
-       cfg->tag = WL1271_SCAN_DEFAULT_TAG;
-       /* don't filter on BSS type */
-       cfg->bss_type = SCAN_BSS_TYPE_ANY;
-       /* currently NL80211 supports only a single interval */
-       for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
-               cfg->intervals[i] = cpu_to_le32(req->interval);
-
-       cfg->ssid_len = 0;
-       ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
-       if (ret < 0)
-               goto out;
-
-       cfg->filter_type = ret;
-
-       wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
-
-       if (!wlcore_set_scan_chan_params(wl, cfg, req->channels,
-                                        req->n_channels, req->n_ssids)) {
-               wl1271_error("scan channel list is empty");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (!force_passive && cfg->active[0]) {
-               u8 band = IEEE80211_BAND_2GHZ;
-               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-                                                wlvif->role_id, band,
-                                                req->ssids[0].ssid,
-                                                req->ssids[0].ssid_len,
-                                                ies->ie[band],
-                                                ies->len[band], true);
-               if (ret < 0) {
-                       wl1271_error("2.4GHz PROBE request template failed");
-                       goto out;
-               }
-       }
-
-       if (!force_passive && cfg->active[1]) {
-               u8 band = IEEE80211_BAND_5GHZ;
-               ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-                                                wlvif->role_id, band,
-                                                req->ssids[0].ssid,
-                                                req->ssids[0].ssid_len,
-                                                ies->ie[band],
-                                                ies->len[band], true);
-               if (ret < 0) {
-                       wl1271_error("5GHz PROBE request template failed");
-                       goto out;
-               }
-       }
-
-       wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
-
-       ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
-                             sizeof(*cfg), 0);
-       if (ret < 0) {
-               wl1271_error("SCAN configuration failed");
-               goto out;
-       }
-out:
-       kfree(cfg);
-       return ret;
-}
-
-int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
-{
-       struct wl1271_cmd_sched_scan_start *start;
-       int ret = 0;
-
-       wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
-
-       if (wlvif->bss_type != BSS_TYPE_STA_BSS)
-               return -EOPNOTSUPP;
-
-       if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
-           test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
-               return -EBUSY;
-
-       start = kzalloc(sizeof(*start), GFP_KERNEL);
-       if (!start)
-               return -ENOMEM;
-
-       start->role_id = wlvif->role_id;
-       start->tag = WL1271_SCAN_DEFAULT_TAG;
-
-       ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
-                             sizeof(*start), 0);
-       if (ret < 0) {
-               wl1271_error("failed to send scan start command");
-               goto out_free;
-       }
-
-out_free:
-       kfree(start);
-       return ret;
-}
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
 
 void wl1271_scan_sched_scan_results(struct wl1271 *wl)
 {
@@ -818,31 +421,3 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl)
 
        ieee80211_sched_scan_results(wl->hw);
 }
-
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
-{
-       struct wl1271_cmd_sched_scan_stop *stop;
-       int ret = 0;
-
-       wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
-
-       /* FIXME: what to do if alloc'ing to stop fails? */
-       stop = kzalloc(sizeof(*stop), GFP_KERNEL);
-       if (!stop) {
-               wl1271_error("failed to alloc memory to send sched scan stop");
-               return;
-       }
-
-       stop->role_id = wlvif->role_id;
-       stop->tag = WL1271_SCAN_DEFAULT_TAG;
-
-       ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
-                             sizeof(*stop), 0);
-       if (ret < 0) {
-               wl1271_error("failed to send sched scan stop command");
-               goto out_free;
-       }
-
-out_free:
-       kfree(stop);
-}
index 29f3c8d..25b0422 100644 (file)
 
 #include "wlcore.h"
 
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
                const u8 *ssid, size_t ssid_len,
                struct cfg80211_scan_request *req);
-int wl1271_scan_stop(struct wl1271 *wl);
 int wl1271_scan_build_probe_req(struct wl1271 *wl,
                                const u8 *ssid, size_t ssid_len,
                                const u8 *ie, size_t ie_len, u8 band);
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif);
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 void wl1271_scan_complete_work(struct work_struct *work);
 int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                                     struct wl12xx_vif *wlvif,
                                     struct cfg80211_sched_scan_request *req,
                                     struct ieee80211_sched_scan_ies *ies);
 int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
 void wl1271_scan_sched_scan_results(struct wl1271 *wl);
 
 #define WL1271_SCAN_MAX_CHANNELS       24
@@ -66,56 +64,6 @@ enum {
        WL1271_SCAN_STATE_DONE
 };
 
-struct basic_scan_params {
-       /* Scan option flags (WL1271_SCAN_OPT_*) */
-       __le16 scan_options;
-       u8 role_id;
-       /* Number of scan channels in the list (maximum 30) */
-       u8 n_ch;
-       /* This field indicates the number of probe requests to send
-          per channel for an active scan */
-       u8 n_probe_reqs;
-       u8 tid_trigger;
-       u8 ssid_len;
-       u8 use_ssid_list;
-
-       /* Rate bit field for sending the probes */
-       __le32 tx_rate;
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       /* Band to scan */
-       u8 band;
-
-       u8 scan_tag;
-       u8 padding2[2];
-} __packed;
-
-struct basic_scan_channel_params {
-       /* Duration in TU to wait for frames on a channel for active scan */
-       __le32 min_duration;
-       __le32 max_duration;
-       __le32 bssid_lsb;
-       __le16 bssid_msb;
-       u8 early_termination;
-       u8 tx_power_att;
-       u8 channel;
-       /* FW internal use only! */
-       u8 dfs_candidate;
-       u8 activity_detected;
-       u8 pad;
-} __packed;
-
-struct wl1271_cmd_scan {
-       struct wl1271_cmd_header header;
-
-       struct basic_scan_params params;
-       struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-
-       /* src mac address */
-       u8 addr[ETH_ALEN];
-       u8 padding[2];
-} __packed;
-
 struct wl1271_cmd_trigger_scan_to {
        struct wl1271_cmd_header header;
 
@@ -160,43 +108,6 @@ struct conn_scan_ch_params {
        u8  padding[3];
 } __packed;
 
-struct wl1271_cmd_sched_scan_config {
-       struct wl1271_cmd_header header;
-
-       __le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
-
-       s8 rssi_threshold; /* for filtering (in dBm) */
-       s8 snr_threshold;  /* for filtering (in dB) */
-
-       u8 cycles;       /* maximum number of scan cycles */
-       u8 report_after; /* report when this number of results are received */
-       u8 terminate;    /* stop scanning after reporting */
-
-       u8 tag;
-       u8 bss_type; /* for filtering */
-       u8 filter_type;
-
-       u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-
-       u8 n_probe_reqs; /* Number of probes requests per channel */
-
-       u8 passive[SCAN_MAX_BANDS];
-       u8 active[SCAN_MAX_BANDS];
-
-       u8 dfs;
-
-       u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
-                           channels in BG band */
-       u8 role_id;
-       u8 padding[1];
-
-       struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
-       struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
-       struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
-} __packed;
-
-
 #define SCHED_SCAN_MAX_SSIDS 16
 
 enum {
@@ -220,21 +131,27 @@ struct wl1271_cmd_sched_scan_ssid_list {
        u8 padding[2];
 } __packed;
 
-struct wl1271_cmd_sched_scan_start {
-       struct wl1271_cmd_header header;
+struct wlcore_scan_channels {
+       u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+       u8 active[SCAN_MAX_BANDS];  /* number of active scan channels */
+       u8 dfs;            /* number of dfs channels in 5ghz */
+       u8 passive_active; /* number of passive before active channels 2.4ghz */
 
-       u8 tag;
-       u8 role_id;
-       u8 padding[2];
-} __packed;
-
-struct wl1271_cmd_sched_scan_stop {
-       struct wl1271_cmd_header header;
-
-       u8 tag;
-       u8 role_id;
-       u8 padding[2];
-} __packed;
+       struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+       struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+       struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+};
 
+bool
+wlcore_set_scan_chan_params(struct wl1271 *wl,
+                           struct wlcore_scan_channels *cfg,
+                           struct ieee80211_channel *channels[],
+                           u32 n_channels,
+                           u32 n_ssids);
+
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
+                                struct wl12xx_vif *wlvif,
+                                struct cfg80211_sched_scan_request *req);
 
 #endif /* __WL1271_SCAN_H__ */
index cf6dbee..2844f30 100644 (file)
@@ -1135,6 +1135,7 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 
        return BIT(__ffs(rate_set));
 }
+EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get);
 
 void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
                              enum wlcore_queue_stop_reason reason)
index b636f1d..9f82ee3 100644 (file)
@@ -82,6 +82,14 @@ struct wlcore_ops {
        int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
        int (*handle_static_data)(struct wl1271 *wl,
                                  struct wl1271_static_data *static_data);
+       int (*scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                         struct cfg80211_scan_request *req);
+       int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+       void (*scan_completed)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+       int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                               struct cfg80211_sched_scan_request *req,
+                               struct ieee80211_sched_scan_ies *ies);
+       void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
        int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
        int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
                       struct ieee80211_vif *vif,
@@ -370,6 +378,11 @@ struct wl1271 {
        const char *sr_fw_name;
        const char *mr_fw_name;
 
+       u8 scan_templ_id_2_4;
+       u8 scan_templ_id_5;
+       u8 sched_scan_templ_id_2_4;
+       u8 sched_scan_templ_id_5;
+
        /* per-chip-family private structure */
        void *priv;