void cw1200_scan_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.work); struct ieee80211_channel **it; struct wsm_scan scan = { .type = WSM_SCAN_TYPE_FOREGROUND, .flags = WSM_SCAN_FLAG_SPLIT_METHOD, }; bool first_run = (priv->scan.begin == priv->scan.curr && priv->scan.begin != priv->scan.end); int i; if (first_run) { /* Firmware gets crazy if scan request is sent * when STA is joined but not yet associated. * Force unjoin in this case. */ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) cw1200_join_timeout(&priv->join_timeout.work); } mutex_lock(&priv->conf_mutex); if (first_run) { if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.mode = WSM_PSM_PS; cw1200_set_pm(priv, &pm); } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ cw1200_disable_listening(priv); } } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { struct cfg80211_scan_info info = { .aborted = priv->scan.status ? 1 : 0, }; if (priv->scan.output_power != priv->output_power) wsm_set_output_power(priv, priv->output_power * 10); if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) wiphy_warn(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); else wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan canceled.\n"); priv->scan.req = NULL; cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); ieee80211_scan_completed(priv->hw, &info); up(&priv->scan.lock); return; } else { struct ieee80211_channel *first = *priv->scan.curr; for (it = priv->scan.curr + 1, i = 1; it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_NO_IR) break; if (!(first->flags & IEEE80211_CHAN_NO_IR) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (priv->scan.req->no_cck) scan.max_tx_rate = WSM_TRANSMIT_RATE_6; else scan.max_tx_rate = WSM_TRANSMIT_RATE_1; scan.num_probes = (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; scan.num_ssids = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.num_channels = it - priv->scan.curr; /* TODO: Is it optimal? */ scan.probe_delay = 100; /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == CW1200_JOIN_STATUS_STA) { scan.type = WSM_SCAN_TYPE_BACKGROUND; scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kcalloc(it - priv->scan.curr, sizeof(struct wsm_scan_ch), GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.num_channels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { scan.ch[i].min_chan_time = 50; scan.ch[i].max_chan_time = 100; } else { scan.ch[i].min_chan_time = 10; scan.ch[i].max_chan_time = 25; } } if (!(first->flags & IEEE80211_CHAN_NO_IR) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; wsm_set_output_power(priv, priv->scan.output_power * 10); } priv->scan.status = cw1200_scan_start(priv, &scan); kfree(scan.ch); if (priv->scan.status) goto fail; priv->scan.curr = it; } mutex_unlock(&priv->conf_mutex); return; fail: priv->scan.curr = priv->scan.end; mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return; }
void cw1200_scan_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.work); struct ieee80211_channel **it; struct wsm_scan scan = { .scanType = WSM_SCAN_TYPE_FOREGROUND, .scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, }; bool first_run = priv->scan.begin == priv->scan.curr && priv->scan.begin != priv->scan.end; int i; mutex_lock(&priv->conf_mutex); if (first_run) { if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_PS; cw1200_set_pm(priv, &pm); } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ cw1200_disable_listening(priv); } } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { if (priv->scan.output_power != priv->output_power) WARN_ON(wsm_set_output_power(priv, priv->output_power * 10)); if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); else wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan canceled.\n"); priv->scan.req = NULL; cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); up(&priv->scan.lock); return; } else { struct ieee80211_channel *first = *priv->scan.curr; for (it = priv->scan.curr + 1, i = 1; it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_PASSIVE_SCAN) break; if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (priv->scan.req->no_cck) scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; else scan.maxTransmitRate = WSM_TRANSMIT_RATE_1; /* TODO: Is it optimal? */ scan.numOfProbeRequests = (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2; scan.numOfSSIDs = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.numOfChannels = it - priv->scan.curr; scan.probeDelay = 100; /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == CW1200_JOIN_STATUS_STA) { scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kzalloc( sizeof(struct wsm_scan_ch[it - priv->scan.curr]), GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.numOfChannels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { scan.ch[i].minChannelTime = 50; scan.ch[i].maxChannelTime = 100; } else { scan.ch[i].minChannelTime = 10; scan.ch[i].maxChannelTime = 25; } } if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; WARN_ON(wsm_set_output_power(priv, priv->scan.output_power * 10)); } priv->scan.status = cw1200_scan_start(priv, &scan); kfree(scan.ch); if (priv->scan.status) goto fail; priv->scan.curr = it; } mutex_unlock(&priv->conf_mutex); return; fail: priv->scan.curr = priv->scan.end; mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return; }