mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-14 15:54:15 +08:00
mac80211: add suspend/resume callbacks
This patch introduces suspend and resume callbacks to mac80211, allowing mac80211 to quiesce its state (bringing down interfaces, removing keys, etc) in preparation for suspend. cfg80211 will call the suspend hook before the device suspend, and resume hook after the device resume. Signed-off-by: Bob Copeland <me@bobcopeland.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
0378b3f1c4
commit
665af4fc89
@ -38,6 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
|
||||
mesh_plink.o \
|
||||
mesh_hwmp.o
|
||||
|
||||
mac80211-$(CONFIG_PM) += pm.o
|
||||
|
||||
# objects for PID algorithm
|
||||
rc80211_pid-y := rc80211_pid_algo.o
|
||||
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
|
||||
|
@ -1256,6 +1256,21 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ieee80211_suspend(struct wiphy *wiphy)
|
||||
{
|
||||
return __ieee80211_suspend(wiphy_priv(wiphy));
|
||||
}
|
||||
|
||||
static int ieee80211_resume(struct wiphy *wiphy)
|
||||
{
|
||||
return __ieee80211_resume(wiphy_priv(wiphy));
|
||||
}
|
||||
#else
|
||||
#define ieee80211_suspend NULL
|
||||
#define ieee80211_resume NULL
|
||||
#endif
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
@ -1286,4 +1301,6 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.set_txq_params = ieee80211_set_txq_params,
|
||||
.set_channel = ieee80211_set_channel,
|
||||
.set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
|
||||
.suspend = ieee80211_suspend,
|
||||
.resume = ieee80211_resume,
|
||||
};
|
||||
|
@ -1006,6 +1006,10 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
|
||||
u16 capab_info, u8 *pwr_constr_elem,
|
||||
u8 pwr_constr_elem_len);
|
||||
|
||||
/* Suspend/resume */
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw);
|
||||
int __ieee80211_resume(struct ieee80211_hw *hw);
|
||||
|
||||
/* utility functions/constants */
|
||||
extern void *mac80211_wiphy_privid; /* for wiphy privid */
|
||||
extern const unsigned char rfc1042_header[6];
|
||||
|
114
net/mac80211/pm.c
Normal file
114
net/mac80211/pm.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include <net/mac80211.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "led.h"
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
struct sta_info *sta;
|
||||
|
||||
flush_workqueue(local->hw.workqueue);
|
||||
|
||||
/* disable keys */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
ieee80211_disable_keys(sdata);
|
||||
|
||||
/* remove STAs */
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
|
||||
if (local->ops->sta_notify) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_REMOVE, &sta->sta);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove all interfaces */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
netif_running(sdata->dev)) {
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = sdata->dev->dev_addr;
|
||||
local->ops->remove_interface(hw, &conf);
|
||||
}
|
||||
}
|
||||
|
||||
/* stop hardware */
|
||||
if (local->open_count) {
|
||||
ieee80211_led_radio(local, false);
|
||||
local->ops->stop(hw);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_if_init_conf conf;
|
||||
struct sta_info *sta;
|
||||
int res;
|
||||
|
||||
/* restart hardware */
|
||||
if (local->open_count) {
|
||||
res = local->ops->start(hw);
|
||||
|
||||
ieee80211_led_radio(local, hw->conf.radio_enabled);
|
||||
}
|
||||
|
||||
/* add interfaces */
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
netif_running(sdata->dev)) {
|
||||
conf.vif = &sdata->vif;
|
||||
conf.type = sdata->vif.type;
|
||||
conf.mac_addr = sdata->dev->dev_addr;
|
||||
res = local->ops->add_interface(hw, &conf);
|
||||
}
|
||||
}
|
||||
|
||||
/* add STAs back */
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
|
||||
if (local->ops->sta_notify) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
||||
local->ops->sta_notify(hw, &sdata->vif,
|
||||
STA_NOTIFY_ADD, &sta->sta);
|
||||
}
|
||||
}
|
||||
|
||||
/* add back keys */
|
||||
list_for_each_entry(sdata, &local->interfaces, list)
|
||||
if (netif_running(sdata->dev))
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
||||
/* setup RTS threshold */
|
||||
if (local->ops->set_rts_threshold)
|
||||
local->ops->set_rts_threshold(hw, local->rts_threshold);
|
||||
|
||||
/* reconfigure hardware */
|
||||
ieee80211_hw_config(local, ~0);
|
||||
|
||||
netif_addr_lock_bh(local->mdev);
|
||||
ieee80211_configure_filter(local);
|
||||
netif_addr_unlock_bh(local->mdev);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user