diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/event.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 104 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/ps.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/scan.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx_platform_data.c | 21 |
7 files changed, 96 insertions, 64 deletions
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index e0d21797948..25990bd38be 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1835,6 +1835,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->bss_type == BSS_TYPE_IBSS))) return -EINVAL; + /* flush all pending packets */ + wl1271_tx_work_locked(wl); + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { ret = wl12xx_croc(wl, wlvif->dev_role_id); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 00ce794eeba..d3280df68f5 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -267,8 +267,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); if (wl->sched_scanning) { - wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); + wl->sched_scanning = false; } } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c3058419e22..d5f55a149de 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -450,7 +450,16 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, if (wl->state == WL1271_STATE_OFF) goto out; + if (dev->operstate != IF_OPER_UP) + goto out; + /* + * The correct behavior should be just getting the appropriate wlvif + * from the given dev, but currently we don't have a mac80211 + * interface for it. + */ wl12xx_for_each_wlvif_sta(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) continue; @@ -458,7 +467,8 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, if (ret < 0) goto out; - wl1271_check_operstate(wl, wlvif, dev->operstate); + wl1271_check_operstate(wl, wlvif, + ieee80211_get_operstate(vif)); wl1271_ps_elp_sleep(wl); } @@ -2036,6 +2046,11 @@ out: return booted; } +static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) +{ + return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; +} + static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -2184,7 +2199,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, if (ret < 0) goto deinit; - if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + if (wl12xx_dev_role_started(wlvif)) + wl12xx_stop_dev(wl, wlvif); + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); if (ret < 0) goto deinit; @@ -2269,6 +2288,17 @@ out: cancel_work_sync(&wl->recovery_work); } +static int wl12xx_op_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + wl1271_op_remove_interface(hw, vif); + + vif->type = ieee80211_iftype_p2p(new_type, p2p); + vif->p2p = p2p; + return wl1271_op_add_interface(hw, vif); +} + static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool set_assoc) { @@ -2358,25 +2388,18 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) wlvif->rate_set = wlvif->basic_rate_set; } -static bool wl12xx_is_roc(struct wl1271 *wl) -{ - u8 role_id; - - role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES); - if (role_id >= WL12XX_MAX_ROLES) - return false; - - return true; -} - static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool idle) { int ret; + bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + + if (idle == cur_idle) + return 0; if (idle) { /* no need to croc if we weren't busy (e.g. during boot) */ - if (wl12xx_is_roc(wl)) { + if (wl12xx_dev_role_started(wlvif)) { ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) goto out; @@ -2391,7 +2414,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, ACX_KEEP_ALIVE_TPL_INVALID); if (ret < 0) goto out; - set_bit(WL1271_FLAG_IDLE, &wl->flags); + clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); } else { /* The current firmware only supports sched_scan in idle */ if (wl->sched_scanning) { @@ -2402,7 +2425,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, ret = wl12xx_start_dev(wl, wlvif); if (ret < 0) goto out; - clear_bit(WL1271_FLAG_IDLE, &wl->flags); + set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); } out: @@ -2446,7 +2469,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - if (wl12xx_is_roc(wl)) { + if (wl12xx_dev_role_started(wlvif)) { /* roaming */ ret = wl12xx_croc(wl, wlvif->dev_role_id); @@ -2463,7 +2486,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, * not idle. otherwise, CROC will be called * anyway. */ - if (wl12xx_is_roc(wl) && + if (wl12xx_dev_role_started(wlvif) && !(conf->flags & IEEE80211_CONF_IDLE)) { ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) @@ -3010,15 +3033,16 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + test_bit(wlvif->role_id, wl->roc_map)) { + /* don't allow scanning right now */ + ret = -EBUSY; + goto out_sleep; + } + /* cancel ROC before scanning */ - if (wl12xx_is_roc(wl)) { - if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - /* don't allow scanning right now */ - ret = -EBUSY; - goto out_sleep; - } + if (wl12xx_dev_role_started(wlvif)) wl12xx_stop_dev(wl, wlvif); - } ret = wl1271_scan(hw->priv, vif, ssid, len, req); out_sleep: @@ -3829,9 +3853,9 @@ sta_not_found: } /* * stop device role if started (we might already be in - * STA role). TODO: make it better. + * STA/IBSS role). */ - if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) { + if (wl12xx_dev_role_started(wlvif)) { ret = wl12xx_stop_dev(wl, wlvif); if (ret < 0) goto out; @@ -3948,31 +3972,8 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, else ps_scheme = CONF_PS_SCHEME_LEGACY; - if (wl->state == WL1271_STATE_OFF) { - /* - * If the state is off, the parameters will be recorded and - * configured on init. This happens in AP-mode. - */ - struct conf_tx_ac_category *conf_ac = - &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)]; - struct conf_tx_tid *conf_tid = - &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)]; - - conf_ac->ac = wl1271_tx_get_queue(queue); - conf_ac->cw_min = (u8)params->cw_min; - conf_ac->cw_max = params->cw_max; - conf_ac->aifsn = params->aifs; - conf_ac->tx_op_limit = params->txop << 5; - - conf_tid->queue_id = wl1271_tx_get_queue(queue); - conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF; - conf_tid->tsid = wl1271_tx_get_queue(queue); - conf_tid->ps_scheme = ps_scheme; - conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; - conf_tid->apsd_conf[0] = 0; - conf_tid->apsd_conf[1] = 0; + if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) goto out; - } ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) @@ -4629,6 +4630,7 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, + .change_interface = wl12xx_op_change_interface, #ifdef CONFIG_PM .suspend = wl1271_op_suspend, .resume = wl1271_op_resume, diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index a7a11088dd3..a2bdacdd7e1 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -53,8 +53,11 @@ void wl1271_elp_work(struct work_struct *work) goto out; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + goto out; + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && - !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) goto out; } @@ -78,8 +81,11 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) return; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return; + if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) && - !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return; } diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 8599dab1fe2..e24111ececc 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -437,18 +437,19 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, if (flags & IEEE80211_CHAN_RADAR) { channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; + channels[j].passive_duration = cpu_to_le16(c->dwell_time_dfs); - } - else if (flags & IEEE80211_CHAN_PASSIVE_SCAN) { + } else { channels[j].passive_duration = cpu_to_le16(c->dwell_time_passive); - } else { - channels[j].min_duration = - cpu_to_le16(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le16(c->max_dwell_time_active); } + + channels[j].min_duration = + cpu_to_le16(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le16(c->max_dwell_time_active); + channels[j].tx_power_att = req->channels[i]->max_power; channels[j].channel = req->channels[i]->hw_value; @@ -703,7 +704,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (wlvif->bss_type != BSS_TYPE_STA_BSS) return -EOPNOTSUPP; - if (!test_bit(WL1271_FLAG_IDLE, &wl->flags)) + if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return -EBUSY; start = kzalloc(sizeof(*start), GFP_KERNEL); @@ -753,7 +754,6 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl) wl1271_error("failed to send sched scan stop command"); goto out_free; } - wl->sched_scanning = false; out_free: kfree(stop); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index d21f71ff6f6..b2b09cd0202 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -241,7 +241,6 @@ enum wl12xx_flags { WL1271_FLAG_IN_ELP, WL1271_FLAG_ELP_REQUESTED, WL1271_FLAG_IRQ_RUNNING, - WL1271_FLAG_IDLE, WL1271_FLAG_FW_TX_BUSY, WL1271_FLAG_DUMMY_PACKET_PENDING, WL1271_FLAG_SUSPENDED, @@ -262,6 +261,7 @@ enum wl12xx_vif_flags { WLVIF_FLAG_PSPOLL_FAILURE, WLVIF_FLAG_CS_PROGRESS, WLVIF_FLAG_AP_PROBE_RESP_SET, + WLVIF_FLAG_IN_USE, }; struct wl1271_link { diff --git a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c index 3c96b332184..998e95895f9 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_platform_data.c +++ b/drivers/net/wireless/wl12xx/wl12xx_platform_data.c @@ -1,3 +1,24 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2010-2011 Texas Instruments, Inc. + * + * 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/module.h> #include <linux/err.h> #include <linux/wl12xx.h> |