>From 0d2ecb4947f18143e152874853c0dcf36f79d597 Mon Sep 17 00:00:00 2001
From: Burak Simsek <burak.simsekfokus.fraunhofer.de>
Date: Tue, 14 Sep 2010 10:35:22 +0200
Subject: [PATCH 2/2] Add the WoW patch of Luis
 http://www.mk.kernel.org/pub/linux/kernel/people/mcgrof/patches/wow-07-21.patch

---
 drivers/net/wireless/ath/ath5k/base.c            |    4 +-
 drivers/net/wireless/ath/ath9k/Makefile          |    1 +
 drivers/net/wireless/ath/ath9k/ar9002_hw.c       |   13 ++
 drivers/net/wireless/ath/ath9k/ar9002_initvals.h |   32 ++++
 drivers/net/wireless/ath/ath9k/ath9k.h           |   20 +++
 drivers/net/wireless/ath/ath9k/eeprom.h          |    1 +
 drivers/net/wireless/ath/ath9k/eeprom_def.c      |    2 +
 drivers/net/wireless/ath/ath9k/hw.c              |   48 +++++++
 drivers/net/wireless/ath/ath9k/hw.h              |   62 ++++++++
 drivers/net/wireless/ath/ath9k/main.c            |   26 ++++-
 drivers/net/wireless/ath/ath9k/pci.c             |  148 +++++++++++++++++++
 drivers/net/wireless/ath/ath9k/reg.h             |  153 ++++++++++++++++++++-
 drivers/net/wireless/mwl8k.c                     |    2 +-
 drivers/net/wireless/rt2x00/rt2x00.h             |    2 +-
 drivers/net/wireless/rt2x00/rt2x00mac.c          |    2 +-
 drivers/net/wireless/rtl818x/rtl8187_dev.c       |    2 +-
 include/linux/nl80211.h                          |   37 +++++
 include/net/cfg80211.h                           |   43 +++++-
 include/net/mac80211.h                           |   16 ++-
 net/mac80211/cfg.c                               |    8 +-
 net/mac80211/driver-ops.h                        |    7 +-
 net/mac80211/ieee80211_i.h                       |   23 ++-
 net/mac80211/iface.c                             |    6 +-
 net/mac80211/mlme.c                              |    3 +-
 net/mac80211/pm.c                                |   67 ++++++++-
 net/mac80211/util.c                              |   31 ++++-
 net/wireless/core.h                              |    3 +
 net/wireless/nl80211.c                           |  165 ++++++++++++++++++++++
 net/wireless/sme.c                               |   14 ++
 net/wireless/sysfs.c                             |    4 +-
 30 files changed, 896 insertions(+), 49 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 116ac66..5b3e5d3 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -224,7 +224,7 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
 		struct ath5k_txq *txq);
 static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
 static int ath5k_start(struct ieee80211_hw *hw);
-static void ath5k_stop(struct ieee80211_hw *hw);
+static void ath5k_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow);
 static int ath5k_add_interface(struct ieee80211_hw *hw,
 		struct ieee80211_vif *vif);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
@@ -3024,7 +3024,7 @@ static int ath5k_start(struct ieee80211_hw *hw)
 	return ath5k_init(hw->priv);
 }
 
-static void ath5k_stop(struct ieee80211_hw *hw)
+static void ath5k_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 {
 	ath5k_stop_hw(hw->priv);
 }
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4555e99..0103ef5 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -10,6 +10,7 @@ ath9k-y +=	beacon.o \
 ath9k-$(CONFIG_PCI) += pci.o
 ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
+ath9k-$(CONFIG_PM) += wow.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 303c63d..3e808d7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -103,6 +103,12 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
 			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
 				  2);
 		}
+#ifdef CONFIG_PM
+		/* SerDes values during WOW sleep */
+		INIT_INI_ARRAY(&ah->iniPcieSerdesWow,
+			       ar9285PciePhy_AWOW_9285_1_2,
+			       ARRAY_SIZE(ar9285PciePhy_AWOW_9285_1_2), 2);
+#endif
 	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
 			       ARRAY_SIZE(ar9280Modes_9280_2), 6);
@@ -118,6 +124,13 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
 			       ar9280PciePhy_clkreq_always_on_L1_9280,
 			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
 		}
+
+	#ifdef CONFIG_PM
+		/* SerDes values during WOW sleep */
+		INIT_INI_ARRAY(&ah->iniPcieSerdesWow, ar9280PciePhy_AWOW_9280,
+			       ARRAY_SIZE(ar9280PciePhy_AWOW_9280), 2);
+	#endif
+
 		INIT_INI_ARRAY(&ah->iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
 			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index 6203eed..930de6d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -919,6 +919,22 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
 	{0x00004044, 0x00000000},
 };
 
+#ifdef CONFIG_PM
+/* Auto generated PCI-E PHY config for AR9280 with WOW */
+static const u_int32_t ar9280PciePhy_AWOW_9280[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01ddffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+#endif
+
 static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
 	/* Addr      allmodes  */
 	{0x00004040, 0x9248fd00},
@@ -1760,6 +1776,22 @@ static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
 	{0x00004044, 0x00000000},
 };
 
+
+#ifdef CONFIG_PM
+static const u_int32_t ar9285PciePhy_AWOW_9285_1_2[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01ddffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+#endif /* CONFIG_PM */
+
 static const u32 ar9287Modes_9287_1_1[][6] = {
 	{0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0},
 	{0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index f0197a6..d61ea8f 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -589,6 +589,13 @@ struct ath_softc {
 
 	int beacon_interval;
 
+#ifdef CONFIG_PM
+	bool wow_got_bmiss_intr;
+	bool wow_sleep_proc_intr;
+	u32 wow_intr_before_sleep;
+	u32 wow_triggers_enabled;
+#endif
+
 #ifdef CONFIG_ATH9K_DEBUGFS
 	struct ath9k_debug debug;
 #endif
@@ -599,6 +606,19 @@ struct ath_softc {
 	struct ath_descdma txsdma;
 };
 
+#ifdef CONFIG_PM
+/*
+ * WoW trigger types
+ */
+#define AH_WOW_USER_PATTERN_EN		0x1
+#define AH_WOW_MAGIC_PATTERN_EN		0x2
+#define AH_WOW_LINK_CHANGE		0x4
+#define AH_WOW_BEACON_MISS		0x8
+#define AH_WOW_MAX_EVENTS		4
+
+#endif
+
+
 struct ath_wiphy {
 	struct ath_softc *sc; /* shared for all virtual wiphys */
 	struct ieee80211_hw *hw;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 0b09db0..6a7317f 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -239,6 +239,7 @@ enum eeprom_param {
 	EEP_MAC_MSW,
 	EEP_MAC_MID,
 	EEP_MAC_LSW,
+	EEP_WOW,
 	EEP_REG_0,
 	EEP_REG_1,
 	EEP_OP_CAP,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index afa2b73..921eee1 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -249,6 +249,8 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
 		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
 	case EEP_MAC_MSW:
 		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_WOW:
+		return pBase->eepMisc & BIT(1);
 	case EEP_REG_0:
 		return pBase->regDmn[0];
 	case EEP_REG_1:
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 3384ca1..10bcdb2 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -22,6 +22,8 @@
 #include "hw-ops.h"
 #include "rc.h"
 #include "ar9003_mac.h"
+#include "ar9002_initvals.h"
+
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
@@ -545,6 +547,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
 		ah->config.serialize_regmode);
 
+
 	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
 		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
 	else
@@ -605,6 +608,16 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 		return r;
 	}
 
+	#ifdef CONFIG_PM
+	/* WOW */
+	ath9k_wow_set_gpio_reset_low(ah);
+	/* Clear the Wow Status */
+	REG_WRITE(ah, AR_PCIE_PM_CTRL, REG_READ(ah, AR_PCIE_PM_CTRL) |
+		  AR_PMCTRL_WOW_PME_CLR);
+	REG_WRITE(ah, AR_WOW_PATTERN_REG,
+		  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN_REG)));
+	#endif
+
 	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
 		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
 	else
@@ -617,6 +630,18 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	return 0;
 }
 
+void ath9k_wow_set_gpio_reset_low(struct ath_hw *ah)
+{
+    u32 val;
+
+    val = REG_READ(ah, AR_GPIO_OE_OUT);
+    val |= (1 << (2 * 2));
+    REG_WRITE(ah, AR_GPIO_OE_OUT, val);
+    val = REG_READ(ah, AR_GPIO_OE_OUT);
+    val = REG_READ(ah,AR_GPIO_IN_OUT );
+}
+
+
 int ath9k_hw_init(struct ath_hw *ah)
 {
 	int ret;
@@ -2078,6 +2103,29 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 			  "regdomain mapped to 0x%x\n", regulatory->current_rd);
 	}
 
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_WOW);
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		/*
+		 * Devices >= AR9280 rev 10 are capable of WoW but require
+		 * a few hardware changes. The EEPROM tells us whether these
+		 * hardware changes are in place on the device. Just enabling
+		 * WoW on the EEPROM is not enough to enable WoW.
+		 */
+		pCap->wow |= ATH9K_WOW_DEVICE_CAPABLE;
+		if (eeval) {
+			pCap->wow |= ATH9K_WOW_HW_ENABLED;
+			pCap->wow |= ATH9K_WOW_PATTERN_MATCH_EXACT;
+			/*
+			 * First 4 bytes of all patterns must match,
+			 * requires some wide masks to ensure proper
+			 * functionality for the disassociation and
+			 * deauthentication frames.
+			 */
+			if (AR_SREV_9280(ah))
+				pCap->wow |= ATH9K_WOW_PATTERN_MATCH_DWORD;
+		}
+	}
+
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
 	if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
 		ath_print(common, ATH_DBG_FATAL,
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 1601dd4..a89351c 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -206,6 +206,42 @@ enum ath9k_hw_caps {
 	ATH9K_HW_CAP_PAPRD			= BIT(22),
 };
 
+/**
+ * enum ath9k_hw_wow_caps - WoW device capabilities
+ *
+ * @ATH9K_WOW_DEVICE_CAPABLE: device revision is capable of WoW
+ * @ATH9K_WOW_HW_ENABLED: EEPROM indicates hardware changes for WoW
+ *	*should be* are present. Devices need some the PCI Wake signal to go
+ *	through, this signal is typically capped with a resistor.
+ *	Devices with WoW physically enabled have this resistor
+ *	shorted to 0 ohm and also have the register that PCI core
+ *	picks up as PCI PME capable enabled.
+ * ATH9K_WOW_PATTERN_MATCH_EXACT: device is capable of matching
+ *	an exact pattern for de-authentication and disassocation.
+ * ATH9K_WOW_PATTERN_MATCH_DWORD: device requires the first four
+ *	bytes of the pattern for deauthentication and disassocation
+ * 	to match for all types of possible frames received of those
+ *	types.
+ */
+enum ath9k_hw_wow_caps {
+	ATH9K_WOW_DEVICE_CAPABLE		= BIT(0),
+	ATH9K_WOW_HW_ENABLED			= BIT(1),
+	ATH9K_WOW_PATTERN_MATCH_EXACT		= BIT(2),
+	ATH9K_WOW_PATTERN_MATCH_DWORD		= BIT(3),
+};
+
+
+/**
+ * struct ath9k_hw_capabilities - device capabilities
+ *
+ * This structure contains the device capabilities. The EEPROM will
+ * be read and specific device capabilities are mapped accordingly
+ * for easy access.
+ *
+ * wow: Wake-on-Wireless LAN capabilities, can be any of the
+ * 	%ATH9K_WOW_*.
+ */
+
 struct ath9k_hw_capabilities {
 	u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
 	DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
@@ -221,6 +257,7 @@ struct ath9k_hw_capabilities {
 	u8 num_gpio_pins;
 	u8 num_antcfg_2ghz;
 	u8 num_antcfg_5ghz;
+	u32 wow;
 	u8 rx_hp_qdepth;
 	u8 rx_lp_qdepth;
 	u8 rx_status_len;
@@ -785,6 +822,13 @@ struct ath_hw {
 	int PDADCdelta;
 	u8 led_pin;
 
+
+#ifdef CONFIG_PM
+	/* WoW mask -- used to indicate which WoW we have enabled */
+	u32 ah_wowEventMask;
+#endif
+
+
 	struct ar5416IniArray iniModes;
 	struct ar5416IniArray iniCommon;
 	struct ar5416IniArray iniBank0;
@@ -815,6 +859,11 @@ struct ath_hw {
 	struct ar5416IniArray iniRadio[ATH_INI_NUM_SPLIT];
 	struct ar5416IniArray iniSOC[ATH_INI_NUM_SPLIT];
 
+#ifdef CONFIG_PM
+	/* SerDes values during WOW sleep */
+	struct ar5416IniArray iniPcieSerdesWow;
+#endif
+
 	u32 intr_gen_timer_trigger;
 	u32 intr_gen_timer_thresh;
 	struct ath_gen_timer_table hw_gen_timers;
@@ -1005,4 +1054,17 @@ void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah);
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
 #define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
 
+#ifdef CONFIG_PM
+
+/* WOW - Wake on Wireless */
+void ath9k_wow_set_gpio_reset_low(struct ath_hw *ah);
+/* Called when going to suspend/hibernate */
+void ath9k_hw_wow_enable(struct ath_hw *ah, u32 patternEnable);
+/* Called when coming back up from suspend/hibernation */
+u32 ath9k_hw_wow_wake_up(struct ath_hw *ah);
+const char *ath9k_hw_wow_event_to_string(u32 wow_event);
+
+#endif /* CONFIG_PM */
+
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a57ead1..4344a87 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -645,7 +645,7 @@ irqreturn_t ath_isr(int irq, void *dev)
 	struct ath_hw *ah = sc->sc_ah;
 	enum ath9k_int status;
 	bool sched = false;
-
+	struct ath_common *common = ath9k_hw_common(ah);
 	/*
 	 * The hardware is not ready/present, don't
 	 * touch anything. Note this can happen early
@@ -725,6 +725,21 @@ irqreturn_t ath_isr(int irq, void *dev)
 		ath9k_hw_set_interrupts(ah, ah->imask);
 	}
 
+	if (status & ATH9K_INT_BMISS) {
+	#ifdef CONFIG_PM
+		if (sc->wow_sleep_proc_intr) {
+			ath_print(common, (ATH_DBG_ANY | ATH_DBG_INTERRUPT),
+				"during WoW we got a BMISS\n");
+			sc->wow_got_bmiss_intr = true;
+			sc->wow_sleep_proc_intr = false;
+		}
+	#else
+		/* BMISS not enabled on ath9k unless WoW is enabled */
+		ath_print(sc, ATH_DBG_INTERRUPT,
+			"spurious unattended beacon miss interrupt\n");
+	#endif
+	}
+
 	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
 		if (status & ATH9K_INT_TIM_TIMER) {
 			/* Clear RxAbort bit so that we can
@@ -1320,6 +1335,15 @@ static void ath9k_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 		cancel_work_sync(&sc->chan_work);
 	}
 
+#ifdef CONFIG_PM
+	if (wow && wow->triggers_enabled) {
+		sc->wow_triggers_enabled = wow->triggers_enabled;
+		ath_print(common, ATH_DBG_ANY, "Leaving radio on during "
+			"suspend for WoW\n");
+		return;
+	}
+#endif
+
 	if (sc->sc_flags & SC_OP_INVALID) {
 		ath_print(common, ATH_DBG_ANY, "Device not present\n");
 		mutex_unlock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index b5b6514..8311a0a 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -156,6 +156,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if ((val & 0x0000ff00) != 0)
 		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
+	device_init_wakeup(&pdev->dev, 1);
+	device_set_wakeup_enable(&pdev->dev, 0);
+
 	ret = pci_request_region(pdev, 0, "ath9k");
 	if (ret) {
 		dev_err(&pdev->dev, "PCI memory region reserve error\n");
@@ -212,6 +215,34 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
 		   hw_name, (unsigned long)mem, pdev->irq);
 
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	/* WoW is for PCI for ath9k */
+
+	/*
+	 * Bmiss and link change triggers not yet fully tested, add them
+	 * after properly testing and confirming behaviour. I believe
+	 * we need pattern matching support to enable them as well
+	 * (detect deauth and disassoc).
+	 */
+	if (ah->caps.wow & ATH9K_WOW_DEVICE_CAPABLE &&
+	    ah->caps.wow & ATH9K_WOW_HW_ENABLED)
+		hw->wiphy->wow_triggers_supported =
+				NL80211_WOW_TRIGGER_MAGIC_PACKET;
+
+	ath_print(common, ATH_DBG_CONFIG,
+		"WoW capabler device: %s\n",
+		(ah->caps.wow & ATH9K_WOW_DEVICE_CAPABLE) ? "yes" : "no");
+	ath_print(common, ATH_DBG_CONFIG,
+		"EEPROM indicates WoW hw changes in place: %s\n",
+		(ah->caps.wow & ATH9K_WOW_HW_ENABLED) ? "yes" : "no");
+	ath_print(common, ATH_DBG_CONFIG,
+		"WoW exact match pattern support: %s\n",
+		(ah->caps.wow & ATH9K_WOW_PATTERN_MATCH_EXACT) ? "yes" : "no");
+	ath_print(common, ATH_DBG_CONFIG,
+		"WoW match pattern first dword requirement: %s\n",
+		(ah->caps.wow & ATH9K_WOW_PATTERN_MATCH_DWORD) ? "yes" : "no");
+
 	return 0;
 
 err_init:
@@ -247,21 +278,134 @@ static void ath_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
+static u32 ath9k_wow_event_map(u32 cfg_wow_events)
+{
+	u32 wow_events = 0;
+
+	if (cfg_wow_events & NL80211_WOW_TRIGGER_MAGIC_PACKET)
+		wow_events |= AH_WOW_MAGIC_PATTERN_EN;
+#if 0
+	if (cfg_wow_events & NL80211_WOW_TRIGGER_BMISS)
+		wow_events |= AH_WOW_BEACON_MISS;
+	if (cfg_wow_events & NL80211_WOW_TRIGGER_LINK_CHANGE)
+		wow_events |= AH_WOW_LINK_CHANGE;
+#endif
+
+	return wow_events;
+}
+
+static void ath9k_pci_wow_enable(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	u32 wake_up_events;
+	struct ath_common *common = ath9k_hw_common(ah);
+	wake_up_events = ath9k_wow_event_map(sc->wow_triggers_enabled);
+
+	/* eventually we'll add this...
+	 * if (wake_up_events & AH_WOW_USER_PATTERN_EN)
+	 *	ath9k_wow_create_pattern(sc);
+	 */
+
+	/*
+	 * To avoid false wake, we enable beacon miss interrupt only when
+	 * we go to sleep. We save the current interrupt mask so that
+	 * we can restore it after the system wakes up.
+	 */
+	//burak> resmen uctum burada
+	sc->wow_intr_before_sleep = ah->imask;
+	ath9k_hw_set_interrupts(ah, ATH9K_INT_BMISS | ATH9K_INT_GLOBAL);
+	ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
+
+	ath9k_hw_wow_enable(ah, wake_up_events);
+	device_set_wakeup_enable(sc->dev, 1);
+
+	ath_print(common, ATH_DBG_ANY,
+		"WoW enabled\n");
+
+	sc->wow_sleep_proc_intr = true;
+
+	/*
+	sc->wow_intr_before_sleep = ah->mask_reg;
+		ath9k_hw_set_interrupts(ah, ATH9K_INT_BMISS | ATH9K_INT_GLOBAL);
+		sc->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
+
+		ath9k_hw_wow_enable(ah, wake_up_events);
+		device_set_wakeup_enable(sc->dev, 1);
+
+		DPRINTF(sc, ATH_DBG_ANY,
+			"WoW enabled\n");
+
+		sc->wow_sleep_proc_intr = true;
+	*/
+
+
+}
+
+
 static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 
+	if (!!sc->wow_triggers_enabled && device_can_wakeup(&pdev->dev))
+		ath9k_pci_wow_enable(sc);
+
 	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
 
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
+
+
+	if (!!sc->wow_triggers_enabled && device_can_wakeup(&pdev->dev)) {
+		pci_prepare_to_sleep(pdev);
+		return 0;
+	}
+
+	pci_wake_from_d3(pdev, !!sc->wow_triggers_enabled);
+
 	pci_set_power_state(pdev, PCI_D3hot);
 
 	return 0;
 }
 
+
+static void ath9k_pci_wow_wake(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	u32 wow_status;
+
+	ath9k_hw_set_interrupts(ah, sc->wow_intr_before_sleep);
+	ah->imask = sc->wow_intr_before_sleep;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	wow_status = ath9k_hw_wow_wake_up(sc->sc_ah);
+
+	if (sc->wow_got_bmiss_intr) {
+		/*
+		 * Some devices may not pick beacon miss
+		 * as the reason they woke up so we add that
+		 * here for that shortcoming
+		 */
+		wow_status |= AH_WOW_BEACON_MISS;
+		sc->wow_got_bmiss_intr = false;
+		ath_print(common, ATH_DBG_ANY,
+			"Beacon miss interrupt picked up during sleep, "
+			"adding as possible wake up reason\n");
+	}
+
+	if (wow_status) {
+		ath_print(common, ATH_DBG_ANY,
+			"Waking up due to WoW trigger%s\n",
+			ath9k_hw_wow_event_to_string(wow_status));
+		ath_print(common, ATH_DBG_ANY,
+			"WoW status: %d\n WoW reason: %s\n",
+			wow_status,
+			ath9k_hw_wow_event_to_string((wow_status & 0x0FFF)));
+	}
+}
+
+
 static int ath_pci_resume(struct pci_dev *pdev)
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
@@ -285,6 +429,10 @@ static int ath_pci_resume(struct pci_dev *pdev)
 	if ((val & 0x0000ff00) != 0)
 		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
+	if (sc->wow_triggers_enabled)
+		ath9k_pci_wow_wake(sc);
+
+
 	/* Enable LED */
 	ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d01c4ad..2891d65 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -707,8 +707,9 @@
 #define AR_WA_D3_TO_L1_DISABLE_REAL     (1 << 16)
 #define AR_WA_ASPM_TIMER_BASED_DISABLE  (1 << 17)
 #define AR_WA_RESET_EN                  (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
-#define AR_WA_ANALOG_SHIFT              (1 << 20)
-#define AR_WA_POR_SHORT                 (1 << 21) /* PCI-E Phy reset control */
+#define AR_WA_UNTIE_RESET_EN	(1 << 15)   /* Enable PCI Reset to POR (power-on-reset) */
+#define AR_WA_ANALOG_SHIFT	(1 << 20)
+#define AR_WA_POR_SHORT		(1 << 21)   /* PCI-E Phy reset control */
 #define AR9285_WA_DEFAULT		0x004a050b
 #define AR9280_WA_DEFAULT           	0x0040073b
 #define AR_WA_DEFAULT               	0x0000073f
@@ -1824,6 +1825,154 @@ enum {
 #define AR_KEYTABLE_TYPE(_n)    (AR_KEYTABLE(_n) + 20)
 #define AR_KEYTABLE_MAC0(_n)    (AR_KEYTABLE(_n) + 24)
 #define AR_KEYTABLE_MAC1(_n)    (AR_KEYTABLE(_n) + 28)
+/* WoW - Wake On Wireless */
+
+#define AR_PMCTRL_AUX_PWR_DET		0x10000000  /* Puts Chip in L2 state */
+#define AR_PMCTRL_D3COLD_VAUX		0x00800000
+#define AR_PMCTRL_HOST_PME_EN		0x00400000    /* Send OOB WAKE_L on WoW event */
+#define AR_PMCTRL_WOW_PME_CLR		0x00200000    /* Clear WoW event */
+#define AR_PMCTRL_PWR_STATE_MASK	0x0F000000    /* Power State Mask */
+#define AR_PMCTRL_PWR_STATE_D1D3	0x0F000000    /* Activate D1 and D3 */
+#define AR_PMCTRL_PWR_STATE_D0		0x08000000    /* Activate D0 */
+#define AR_PMCTRL_PWR_PM_CTRL_ENA	0x00008000    /* Enable power management */
+
+#define AR_WOW_BEACON_TIMO_MAX		0xFFFFFFFF  /* Max. value for Beacon Timeout */
+
+/*
+ * MAC WoW Registers.
+ */
+#define AR_WOW_PATTERN_REG		0x825C
+#define AR_WOW_COUNT_REG		0x8260
+#define AR_WOW_BCN_EN_REG		0x8270
+#define AR_WOW_BCN_TIMO_REG		0x8274
+#define AR_WOW_KEEP_ALIVE_TIMO_REG	0x8278
+#define AR_WOW_KEEP_ALIVE_REG		0x827C
+#define AR_WOW_US_SCALAR_REG		0x8284
+#define AR_WOW_KEEP_ALIVE_DELAY_REG	0x8288
+#define AR_WOW_PATTERN_MATCH_REG	0x828C
+#define AR_WOW_PATTERN_OFF1_REG		0x8290 /* Pattern bytes 0 -> 3 */
+#define AR_WOW_PATTERN_OFF2_REG		0x8294 /* Pattern bytes 4 -> 7 */
+/* For AR9285 or Later version of chips */
+#define AR_WOW_EXACT_REG		0x829C
+#define AR_WOW_LENGTH1_REG		0x8360
+#define AR_WOW_LENGTH2_REG		0x8364
+/* Register to enable pattern match for less than 256 bytes packets */
+#define AR_WOW_PATTERN_MATCH_LT_256B_REG	0x8368
+
+/* AR_WOW_PATTERN_REG Values */
+#define AR_WOW_BACK_OFF_SHIFT(x)	((x & 0xf) << 27)    /* in usecs */
+#define AR_WOW_MAC_INTR_EN		0x00040000
+#define AR_WOW_MAGIC_EN			0x00010000
+#define AR_WOW_PATTERN_EN(x)		((x & 0xff) << 0)
+#define AR_WOW_PATTERN_FOUND_SHIFT	8
+#define AR_WOW_PATTERN_FOUND(x)		(x & (0xff << AR_WOW_PATTERN_FOUND_SHIFT))
+#define AR_WOW_PATTERN_FOUND_MASK	((0xff) << AR_WOW_PATTERN_FOUND_SHIFT)
+#define AR_WOW_MAGIC_PAT_FOUND		0x00020000
+#define AR_WOW_MAC_INTR			0x00080000
+#define AR_WOW_KEEP_ALIVE_FAIL		0x00100000
+#define AR_WOW_BEACON_FAIL		0x00200000
+
+#define AR_WOW_STATUS(x)	(x & (AR_WOW_PATTERN_FOUND_MASK | \
+				      AR_WOW_MAGIC_PAT_FOUND | \
+				      AR_WOW_KEEP_ALIVE_FAIL | \
+				      AR_WOW_BEACON_FAIL))
+#define AR_WOW_CLEAR_EVENTS(x)	(x & ~(AR_WOW_PATTERN_EN(0xff) | \
+				       AR_WOW_MAGIC_EN | \
+				       AR_WOW_MAC_INTR_EN | \
+				       AR_WOW_BEACON_FAIL | \
+				       AR_WOW_KEEP_ALIVE_FAIL))
+
+/* AR_WOW_COUNT_REG Values */
+#define AR_WOW_AIFS_CNT(x)		((x & 0xff) << 0)
+#define AR_WOW_SLOT_CNT(x)		((x & 0xff) << 8)
+#define AR_WOW_KEEP_ALIVE_CNT(x)	((x & 0xff) << 16)
+
+/* AR_WOW_BCN_EN_REG */
+#define AR_WOW_BEACON_FAIL_EN		0x00000001
+
+/* AR_WOW_BCN_TIMO_REG */
+#define AR_WOW_BEACON_TIMO		0x40000000  /* Valid if BCN_EN is set */
+
+/* AR_WOW_KEEP_ALIVE_TIMO_REG */
+#define AR_WOW_KEEP_ALIVE_TIMO		0x00007A12
+#define AR_WOW_KEEP_ALIVE_NEVER		0xFFFFFFFF
+
+/* AR_WOW_KEEP_ALIVE_REG */
+#define AR_WOW_KEEP_ALIVE_AUTO_DIS	0x00000001
+#define AR_WOW_KEEP_ALIVE_FAIL_DIS	0x00000002
+
+/* AR_WOW_KEEP_ALIVE_DELAY_REG */
+#define AR_WOW_KEEP_ALIVE_DELAY		0x000003E8 /* 1 msec */
+
+/*
+ * Keep it long for Beacon workaround - ensures no false alarm
+ */
+#define AR_WOW_BMISSTHRESHOLD 0x20
+
+/* AR_WOW_PATTERN_MATCH_REG */
+#define AR_WOW_PAT_END_OF_PKT(x)	((x & 0xf) << 0)
+#define AR_WOW_PAT_OFF_MATCH(x)		((x & 0xf) << 8)
+
+/*
+ * Default values for Wow Configuration for backoff, aifs, slot, keep-alive, etc
+ * to be programmed into various registers.
+ */
+#define AR_WOW_PAT_BACKOFF	0x00000004 /* AR_WOW_PATTERN_REG */
+#define AR_WOW_CNT_AIFS_CNT	0x00000022 /* AR_WOW_COUNT_REG */
+#define AR_WOW_CNT_SLOT_CNT	0x00000009 /* AR_WOW_COUNT_REG */
+/*
+ * Keepalive count applicable for AR9280 2.0 and above.
+ */
+#define AR_WOW_CNT_KA_CNT 0x00000008    /* AR_WOW_COUNT_REG */
+
+/* WoW - Transmit buffer for keep alive frames */
+#define AR_WOW_TRANSMIT_BUFFER	0xE000 /* E000 - EFFC */
+
+#define AR_WOW_KA_DESC_WORD2	0xE000
+#define AR_WOW_KA_DESC_WORD3	0xE004
+#define AR_WOW_KA_DESC_WORD4	0xE008
+#define AR_WOW_KA_DESC_WORD5	0xE00C
+#define AR_WOW_KA_DESC_WORD6	0xE010
+#define AR_WOW_KA_DESC_WORD7	0xE014
+#define AR_WOW_KA_DESC_WORD8	0xE018
+#define AR_WOW_KA_DESC_WORD9	0xE01C
+#define AR_WOW_KA_DESC_WORD10	0xE020
+#define AR_WOW_KA_DESC_WORD11	0xE024
+#define AR_WOW_KA_DESC_WORD12	0xE028
+#define AR_WOW_KA_DESC_WORD13	0xE02C
+
+#define AR_WOW_KA_DATA_WORD0	0xE030
+#define AR_WOW_KA_DATA_WORD1	0xE034
+#define AR_WOW_KA_DATA_WORD2	0xE038
+#define AR_WOW_KA_DATA_WORD3	0xE03C
+#define AR_WOW_KA_DATA_WORD4	0xE040
+#define AR_WOW_KA_DATA_WORD5	0xE044
+
+/* WoW Transmit Buffer for patterns */
+#define AR_WOW_TB_PATTERN0	0xE100
+#define AR_WOW_TB_PATTERN1	0xE200
+#define AR_WOW_TB_PATTERN2	0xE300
+#define AR_WOW_TB_PATTERN3	0xE400
+#define AR_WOW_TB_PATTERN4	0xE500
+#define AR_WOW_TB_PATTERN5	0xE600
+#define AR_WOW_TB_PATTERN6	0xE700
+#define AR_WOW_TB_PATTERN7	0xE800
+#define AR_WOW_TB_MASK0		0xEC00
+#define AR_WOW_TB_MASK1		0xEC20
+#define AR_WOW_TB_MASK2		0xEC40
+#define AR_WOW_TB_MASK3		0xEC60
+#define AR_WOW_TB_MASK4		0xEC80
+#define AR_WOW_TB_MASK5		0xECa0
+#define AR_WOW_TB_MASK6		0xECC0
+#define AR_WOW_TB_MASK7		0xECE0
+
+/* Currently Pattern 0-7 are supported - so bit 0-7 are set */
+#define AR_WOW_PATTERN_SUPPORTED	0xFF
+#define AR_WOW_LENGTH_MAX		0xFF
+#define AR_WOW_LENGTH1_SHIFT(_i)	((0x3 - ((_i) & 0x3)) << 0x3)
+#define AR_WOW_LENGTH1_MASK(_i)		(AR_WOW_LENGTH_MAX << AR_WOW_LENGTH1_SHIFT(_i))
+#define AR_WOW_LENGTH2_SHIFT(_i)	((0x7 - ((_i) & 0x7)) << 0x3)
+#define AR_WOW_LENGTH2_MASK(_i)		(AR_WOW_LENGTH_MAX << AR_WOW_LENGTH2_SHIFT(_i))
 
 #define AR9271_CORE_CLOCK	117   /* clock to 117Mhz */
 #define AR9271_TARGET_BAUD_RATE	19200 /* 115200 */
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index f152a25..5a711c3 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3256,7 +3256,7 @@ static int mwl8k_start(struct ieee80211_hw *hw)
 	return rc;
 }
 
-static void mwl8k_stop(struct ieee80211_hw *hw)
+static void mwl8k_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 {
 	struct mwl8k_priv *priv = hw->priv;
 	int i;
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0ae942c..0e59b84 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1082,7 +1082,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
  */
 int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int rt2x00mac_start(struct ieee80211_hw *hw);
-void rt2x00mac_stop(struct ieee80211_hw *hw);
+void rt2x00mac_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow);
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 			    struct ieee80211_vif *vif);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 235e037..92a95cd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -175,7 +175,7 @@ int rt2x00mac_start(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_start);
 
-void rt2x00mac_stop(struct ieee80211_hw *hw)
+void rt2x00mac_stop(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 38fa824..f62f464 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -987,7 +987,7 @@ rtl8187_start_exit:
 	return ret;
 }
 
-static void rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev, struct cfg80211_wow *wow)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct sk_buff *skb;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 31603e8..805048c 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -311,6 +311,19 @@
  * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
  *	associated with this wiphy must be down and will follow.
  *
+ * @NL80211_CMD_GET_WOW: get Wake-on-Wireless-LAN (WoW) settings.
+ * @NL80211_CMD_SET_WOW: set Wake-on-Wireless-LAN (Wow) settings. Wake on
+ *	wireless makes use of standard Wake-on-LAN (WoL) frames, you receive
+ *	a WoW frame when your AP sends you a regular WOL frame. The difference
+ *	difference WoL is you need to be associated to an AP in order to
+ *	receive WoW frames, so additional triggers are available for a wakeup.
+ *	A driver capable of WoW should initialize the wiphy with its supported
+ *	WoW triggers. Upon suspend cfg80211 will inform the driver of the user
+ *	enabled triggers. By default no WoW triggers are enabled.
+ *	For more information see:
+ *	http://wireless.kernel.org/en/users/Documentation/WoW
+ *
+ *
  * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
  *	channel for the specified amount of time. This can be used to do
  *	off-channel operations like transmit a Public Action frame and wait for
@@ -462,6 +475,8 @@ enum nl80211_commands {
 	NL80211_CMD_DISCONNECT,
 
 	NL80211_CMD_SET_WIPHY_NETNS,
+	NL80211_CMD_GET_WOW,
+	NL80211_CMD_SET_WOW,
 
 	NL80211_CMD_GET_SURVEY,
 	NL80211_CMD_NEW_SURVEY_RESULTS,
@@ -509,6 +524,8 @@ enum nl80211_commands {
 #define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+#define NL80211_CMD_GET_WOW NL80211_CMD_GET_WOW
+#define NL80211_CMD_SET_WOW NL80211_CMD_SET_WOW
 
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
@@ -736,6 +753,12 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_PID: Process ID of a network namespace.
  *
+ * @NL80211_ATTR_WOW_TRIGGERS_SUPPORTED: the supported WoW triggers
+ * @NL80211_ATTR_WOW_TRIGGERS_ENABLED: used by %NL80211_CMD_SET_WOW to
+ *	indicate which WoW triggers should be enabled. This is also
+ *	used by %NL80211_CMD_GET_WOW to get the currently enabled WoW
+ *	triggers.
+ *
  * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
  *	dumps. This number increases whenever the object list being
  *	dumped changes, and as such userspace can verify that it has
@@ -927,6 +950,9 @@ enum nl80211_attrs {
 	NL80211_ATTR_KEYS,
 
 	NL80211_ATTR_PID,
+	
+	NL80211_ATTR_WOW_TRIGGERS_SUPPORTED,
+	NL80211_ATTR_WOW_TRIGGERS_ENABLED,
 
 	NL80211_ATTR_4ADDR,
 
@@ -1703,6 +1729,17 @@ enum nl80211_key_attributes {
 };
 
 /**
+ * enum nl80211_wow_triggers - Wake-on-Wireless-LAN triggers
+ *
+ * NL80211_WOW_TRIGGER_MAGIC_PACKET: a wake signal will be sent to the
+ *     devices if a magic packet is received.
+ */
+enum nl80211_wow_triggers {
+	NL80211_WOW_TRIGGER_MAGIC_PACKET	= 1 << 1,
+};
+
+
+/**
  * enum nl80211_tx_rate_attributes - TX rate set attributes
  * @__NL80211_TXRATE_INVALID: invalid
  * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4c8c727..2d1ba87 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -780,6 +780,9 @@ struct cfg80211_crypto_settings {
 	bool control_port_no_encrypt;
 };
 
+
+
+
 /**
  * struct cfg80211_auth_request - Authentication request data
  *
@@ -977,6 +980,27 @@ struct cfg80211_pmksa {
 	u8 *pmkid;
 };
 
+
+/*
+ * struct cfg80211_wow - Wake on Wireless-LAN support info
+ *
+ * This structure defines the WoW triggers enabled and set for the device.
+ * For now we only carry the supported tiggers but this is expected to grow
+ * once we add support for user patterns.
+ *
+ * @triggers_enabled: enabled triggers by the user. Default
+ *	is to disable all triggers. The flags for this bitmask
+ *	are %NL80211_WOW_TRIGGER_*.
+ * @netdev: net_device where we enabled WoW. This is only used to clear
+ *	the @triggers_enabled upon disassociation and to prevent settings
+ *	onto other netdevices from the same rdev.
+ */
+struct cfg80211_wow {
+	u32 triggers_enabled;
+	struct net_device *netdev;
+};
+
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -990,8 +1014,11 @@ struct cfg80211_pmksa {
  * wireless extensions but this is subject to reevaluation as soon as this
  * code is used more widely and we have a first user without wext.
  *
- * @suspend: wiphy device needs to be suspended
- * @resume: wiphy device needs to be resumed
+ * @suspend: wiphy device needs to be suspended. We pass the struct cfg80211_wow
+ *	so the device enables the appropriate triggers during suspend.
+ * @resume: wiphy device needs to be resumed. We pass the struct cfg80211_wow
+ * 	so the device can opt out from adding new information for the AP we
+ *	we were last associated to when WoW was enabled
  *
  * @add_virtual_intf: create a new virtual interface with the given name,
  *	must set the struct wireless_dev's iftype. Beware: You must create
@@ -1115,8 +1142,11 @@ struct cfg80211_pmksa {
  *
  */
 struct cfg80211_ops {
-	int	(*suspend)(struct wiphy *wiphy);
-	int	(*resume)(struct wiphy *wiphy);
+//	int	(*suspend)(struct wiphy *wiphy);
+//	int	(*resume)(struct wiphy *wiphy);
+
+	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wow *wow);
+	int	(*resume)(struct wiphy *wiphy, struct cfg80211_wow *wow);
 
 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
 				    enum nl80211_iftype type, u32 *flags,
@@ -1337,6 +1367,10 @@ struct ieee80211_txrx_stypes {
  * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
  *	-1 = fragmentation disabled, only odd values >= 256 used
  * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
+ * @wow_triggers_supported: supported bitmask of Wake-on-Wireless triggers.
+ *	The flags for this bitmask are %NL80211_WOW_TRIGGER_*. The driver
+ *	should set the capabilities before registering the wiphy. WoW triggers
+ *	which should be used are passed to the driver upon suspend.
  * @_net: the network namespace this wiphy currently lives in
  * @perm_addr: permanent MAC address of this device
  * @addr_mask: If the device supports multiple MAC addresses by masking,
@@ -1414,6 +1448,7 @@ struct wiphy {
 	u32 hw_version;
 
 	u8 max_num_pmkids;
+	u32 wow_triggers_supported;
 
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f91fc33..c04b222 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1520,12 +1520,14 @@ enum ieee80211_ampdu_mlme_action {
  *	Must be implemented and can sleep.
  *
  * @stop: Called after last netdevice attached to the hardware
- *	is disabled. This should turn off the hardware (at least
- *	it must turn off frame reception.)
- *	May be called right after add_interface if that rejects
- *	an interface. If you added any work onto the mac80211 workqueue
- *	you should ensure to cancel it on this callback.
- *	Must be implemented and can sleep.
+ *	is disabled or during suspend. This should turn off the
+ *	hardware (at least it must turn off frame reception) unless
+ *	the device wants to enable Wake-on-Wireless-LAN. In order to
+ *	process WoW triggers the radio must be left on and the driver
+ *	must enable the triggers in hardware. This callback may be
+ *	called right after add_interface if that rejects an interface.
+ *	Must be implemented. WoW triggers which should be enabled prior
+ *	suspend are passed in the callback.
  *
  * @add_interface: Called when a netdevice attached to the hardware is
  *	enabled. Because it is not called for monitor mode devices, @start
@@ -1696,7 +1698,7 @@ enum ieee80211_ampdu_mlme_action {
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 	int (*start)(struct ieee80211_hw *hw);
-	void (*stop)(struct ieee80211_hw *hw);
+	void (*stop)(struct ieee80211_hw *hw, struct cfg80211_wow *wow);
 	int (*add_interface)(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif);
 	int (*change_interface)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5de1ca3..ba85860 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1132,14 +1132,14 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
 }
 
 #ifdef CONFIG_PM
-static int ieee80211_suspend(struct wiphy *wiphy)
+static int ieee80211_suspend(struct wiphy *wiphy, struct cfg80211_wow *wow)
 {
-	return __ieee80211_suspend(wiphy_priv(wiphy));
+	return __ieee80211_suspend(wiphy_priv(wiphy) , wow);
 }
 
-static int ieee80211_resume(struct wiphy *wiphy)
+static int ieee80211_resume(struct wiphy *wiphy, struct cfg80211_wow *wow)
 {
-	return __ieee80211_resume(wiphy_priv(wiphy));
+	return __ieee80211_resume(wiphy_priv(wiphy) ,wow);
 }
 #else
 #define ieee80211_suspend NULL
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 6064b7b..82a695d 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -24,12 +24,13 @@ static inline int drv_start(struct ieee80211_local *local)
 	return ret;
 }
 
-static inline void drv_stop(struct ieee80211_local *local)
+static inline void drv_stop(struct ieee80211_local *local, struct cfg80211_wow *wow)
 {
 	might_sleep();
 
-	trace_drv_stop(local);
-	local->ops->stop(&local->hw);
+	trace_drv_stop(local, wow);
+	local->ops->stop(&local->hw, wow);
+
 	trace_drv_return_void(local);
 
 	/* sync away all work on the tasklet before clearing started */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 16f7fb1..5313ecd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -723,6 +723,13 @@ struct ieee80211_local {
 	 * ease timer cancelling etc.
 	 */
 	bool quiescing;
+	/*
+	 * This will be true if we had enabled PS before going to suspend.
+	 * We use this to help resume restore the PS state to what it was.
+	 * Note that this only makes sense if we're associated and are a
+	 * station.
+	 */
+	bool ps_before_suspend;
 
 	/* device is started */
 	bool started;
@@ -1178,23 +1185,25 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 				       size_t len);
 
 /* Suspend/resume and hw reconfiguration */
-int ieee80211_reconfig(struct ieee80211_local *local);
-void ieee80211_stop_device(struct ieee80211_local *local);
+int ieee80211_reconfig(struct ieee80211_local *local, struct cfg80211_wow *wow);
+void ieee80211_stop_device(struct ieee80211_local *local,  struct cfg80211_wow *wow);
 
 #ifdef CONFIG_PM
-int __ieee80211_suspend(struct ieee80211_hw *hw);
+int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wow *wow);
 
-static inline int __ieee80211_resume(struct ieee80211_hw *hw)
+static inline int __ieee80211_resume(struct ieee80211_hw *hw,
+				     struct cfg80211_wow *wow)
 {
-	return ieee80211_reconfig(hw_to_local(hw));
+	return ieee80211_reconfig(hw_to_local(hw), wow);
 }
 #else
-static inline int __ieee80211_suspend(struct ieee80211_hw *hw)
+static inline int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 {
 	return 0;
 }
 
-static inline int __ieee80211_resume(struct ieee80211_hw *hw)
+static inline int __ieee80211_resume(struct ieee80211_hw *hw,
+				     struct cfg80211_wow *wow)
 {
 	return 0;
 }
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index c1cc200..78506a6 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -216,7 +216,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 
 		if (!is_valid_ether_addr(dev->dev_addr)) {
 			if (!local->open_count)
-				drv_stop(local);
+				drv_stop(local,NULL);
 			return -EADDRNOTAVAIL;
 		}
 	}
@@ -338,7 +338,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 	drv_remove_interface(local, &sdata->vif);
  err_stop:
 	if (!local->open_count)
-		drv_stop(local);
+		drv_stop(local,NULL);
  err_del_bss:
 	sdata->bss = NULL;
 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -543,7 +543,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		if (local->ops->napi_poll)
 			napi_disable(&local->napi);
 		ieee80211_clear_tx_pending(local);
-		ieee80211_stop_device(local);
+		ieee80211_stop_device(local,NULL);
 
 		/* no reconfiguring after stop! */
 		hw_reconf_flags = 0;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0cb822c..9072293 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1912,7 +1912,8 @@ static void ieee80211_sta_monitor_work(struct work_struct *work)
 	struct ieee80211_sub_if_data *sdata =
 		container_of(work, struct ieee80211_sub_if_data,
 			     u.mgd.monitor_work);
-
+	if (sdata->local->scanning)
+		return;
 	ieee80211_mgd_probe_ap(sdata, false);
 }
 
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index d287fde..37bd195 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -6,14 +6,68 @@
 #include "driver-ops.h"
 #include "led.h"
 
-int __ieee80211_suspend(struct ieee80211_hw *hw)
+int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wow *wow)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
+	
+	bool wow_netdev_found = false;
 
 	ieee80211_scan_cancel(local);
 
+
+	local->ps_before_suspend = !!(local->hw.conf.flags & IEEE80211_CONF_PS);
+
+	if (wow->triggers_enabled) {
+		if (!local->ps_before_suspend) {
+			local->hw.conf.flags |= IEEE80211_CONF_PS;
+			ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+		}
+
+		del_timer_sync(&local->dynamic_ps_timer);
+		cancel_work_sync(&local->dynamic_ps_enable_work);
+
+		/*
+		 * Send nullfunc PS frame to AP so it can buffer frames for us,
+		 * unless we already are in that PS state. We'll discard all
+		 * frames except the ones our harware will process and use for
+		 * triggering a wake up.
+		 */
+		list_for_each_entry(sdata, &local->interfaces, list) {
+			struct ieee80211_if_managed *ifmgd;
+			if (sdata->dev != wow->netdev)
+				continue;
+			/* WoW only applies to STAs */
+			if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+				continue;
+			ifmgd = &sdata->u.mgd;
+			/*
+			 * cfg80211 should have cleared the
+			 * triggers upon disassociation.
+			 */
+			if (WARN_ON(!ifmgd->associated))
+				continue;
+			if (!local->ps_before_suspend)
+				ieee80211_send_nullfunc(local, sdata, 1);
+			wow_netdev_found = true;
+			break;
+		}
+
+		/*
+		 * WoW triggers should be cleared if the netdev claiming
+		 * it no longer exists
+		 */
+		WARN_ON(!wow_netdev_found);
+
+	}
+
+	if (wow_netdev_found)
+		printk(KERN_DEBUG "mac80211: WoW enabled interface found, "
+		       "will try to enable WoW during suspend\n");
+
+
+
 	ieee80211_stop_queues_by_reason(hw,
 			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
@@ -69,6 +123,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 		switch(sdata->vif.type) {
 		case NL80211_IFTYPE_STATION:
 			ieee80211_sta_quiesce(sdata);
+			/* Don't remove the interface when WoW is enabled */
+			if (sdata->dev != wow->netdev)
+				continue;
 			break;
 		case NL80211_IFTYPE_ADHOC:
 			ieee80211_ibss_quiesce(sdata);
@@ -94,9 +151,11 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 		drv_remove_interface(local, &sdata->vif);
 	}
 
-	/* stop hardware - this must stop RX */
-	if (local->open_count)
-		ieee80211_stop_device(local);
+
+			if (wow_netdev_found)
+				ieee80211_stop_device(local, wow);
+			else if (local->open_count)
+				ieee80211_stop_device(local, NULL);
 
 	local->suspended = true;
 	/* need suspended to be visible before quiescing is false */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index bd40b11..bda9f53 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1083,26 +1083,30 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
 	return supp_rates;
 }
 
-void ieee80211_stop_device(struct ieee80211_local *local)
+void ieee80211_stop_device(struct ieee80211_local *local,  struct cfg80211_wow *wow)
 {
 	ieee80211_led_radio(local, false);
 
 	cancel_work_sync(&local->reconfig_filter);
 
 	flush_workqueue(local->workqueue);
-	drv_stop(local);
+	drv_stop(local, wow);
 }
 
-int ieee80211_reconfig(struct ieee80211_local *local)
+int ieee80211_reconfig(struct ieee80211_local *local, struct cfg80211_wow *wow)
 {
 	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
 	int res;
+	bool from_suspend = local->suspended;
 
 	if (local->suspended)
 		local->resuming = true;
 
+	if (from_suspend && local->ps_before_suspend)
+		local->hw.conf.flags |= IEEE80211_CONF_PS;
+
 	/* restart hardware */
 	if (local->open_count) {
 		/*
@@ -1122,11 +1126,16 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 		ieee80211_led_radio(local, true);
 	}
 
-	/* add interfaces */
+	/*
+	 * Add all interfaces back again. If we had enabled WoW we
+	 * don't need to add the interface as we never removed it
+	 * at suspend.
+	 */
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
 		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-		    ieee80211_sdata_running(sdata))
+		    ieee80211_sdata_running(sdata) &&
+		    sdata->dev != wow->netdev)
 			res = drv_add_interface(local, &sdata->vif);
 	}
 
@@ -1235,6 +1244,18 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 		return 0;
 
 #ifdef CONFIG_PM
+
+	if (!local->ps_before_suspend) {
+		list_for_each_entry(sdata, &local->interfaces, list) {
+			struct ieee80211_if_managed *ifmgd;
+			if (sdata->vif.type != NL80211_IFTYPE_STATION)
+				continue;
+			ifmgd = &sdata->u.mgd;
+			if (ifmgd->associated)
+				ieee80211_send_nullfunc(local, sdata, 0);
+		}
+	}
+
 	/* first set suspended false, then resuming */
 	local->suspended = false;
 	mb();
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 58ab2c7..80c69b0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -69,6 +69,9 @@ struct cfg80211_registered_device {
 
 	struct work_struct conn_work;
 	struct work_struct event_work;
+	
+	/* Used to keep track of user configurable triggers */
+	struct cfg80211_wow wow;
 
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 85a23de..75c73b0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -142,6 +142,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 	[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
 	[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
 	[NL80211_ATTR_PID] = { .type = NLA_U32 },
+	[NL80211_ATTR_WOW_TRIGGERS_SUPPORTED] = { .type = NLA_U32 },
+	[NL80211_ATTR_WOW_TRIGGERS_ENABLED] = { .type = NLA_U32 },
 	[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
 	[NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
 				 .len = WLAN_PMKID_LEN },
@@ -4470,6 +4472,153 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+
+static int nl80211_get_wow(struct sk_buff *skb,
+			   struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev;
+	struct net_device *dev;
+	struct wiphy *wiphy;
+	int err;
+	void *hdr;
+	struct sk_buff *msg;
+
+	rtnl_lock();
+	/* Look up our device */
+	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+	if (err)
+		goto out_rtnl;
+
+	wiphy = &rdev->wiphy;
+
+	/* Draw up a netlink message to send back */
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOBUFS;
+		goto out;
+	}
+	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+			     NL80211_CMD_GET_WOW);
+	if (!hdr)
+		goto nla_put_failure;
+	NLA_PUT_U32(msg, NL80211_ATTR_WOW_TRIGGERS_SUPPORTED,
+		    wiphy->wow_triggers_supported);
+	NLA_PUT_U32(msg, NL80211_ATTR_WOW_TRIGGERS_ENABLED,
+		    rdev->wow.triggers_enabled);
+
+	genlmsg_end(msg, hdr);
+	err = genlmsg_reply(msg, info);
+	goto out;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	err = -EMSGSIZE;
+ out:
+	/* Cleanup */
+	cfg80211_unlock_rdev(rdev);
+	dev_put(dev);
+ out_rtnl:
+	rtnl_unlock();
+
+	return err;
+}
+
+static int nl80211_set_wow(struct sk_buff *skb, struct genl_info *info)
+{
+	int err;
+	struct cfg80211_registered_device *rdev;
+	struct net_device *dev;
+	struct wiphy *wiphy;
+	struct wireless_dev *wdev;
+	u32 triggers_requested;
+
+	if (!info->attrs[NL80211_ATTR_WOW_TRIGGERS_ENABLED])
+		return -EINVAL;
+
+	rtnl_lock();
+
+	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+	if (err)
+		goto out_rtnl;
+
+	wiphy = &rdev->wiphy;
+
+	if (!wiphy->wow_triggers_supported) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	triggers_requested =
+		nla_get_u32(info->attrs[NL80211_ATTR_WOW_TRIGGERS_ENABLED]);
+
+	if (rdev->wow.netdev) {
+		if (rdev->wow.netdev != dev) {
+			err = -EALREADY;
+			goto out;
+		}
+		if (!triggers_requested) {
+			rdev->wow.triggers_enabled = 0;
+			rdev->wow.netdev = NULL;
+			goto out;
+		}
+	}
+
+	/* This would be a no-op as the rdev->wow should be unconfigured */
+	if (!triggers_requested)
+		goto out;
+
+	/* We only support magic packet right now */
+	if (triggers_requested & ~NL80211_WOW_TRIGGER_MAGIC_PACKET) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if ((triggers_requested & wiphy->wow_triggers_supported) !=
+	    triggers_requested) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/*
+	 * It only makes sense to enable WoW if we're associated as a STA,
+	 * the AP should be buffering frames for us. We'll discard all frames
+	 * and only process the frames which will trigger us on in hardware.
+	 */
+	wdev = dev->ieee80211_ptr;
+
+	wdev_lock(wdev);
+
+	if (wdev->iftype != NL80211_IFTYPE_STATION) {
+		err = -EINVAL;
+		wdev_unlock(wdev);
+		goto out;
+	}
+
+	if (wdev->sme_state != CFG80211_SME_CONNECTED) {
+		err = -ENOTCONN;
+		wdev_unlock(wdev);
+		goto out;
+	}
+
+	wdev_unlock(wdev);
+
+	/*
+	 * Apply changes. This information gets passed to the
+	 * drivers during suspend.
+	 */
+	rdev->wow.netdev = dev;
+	rdev->wow.triggers_enabled = triggers_requested;
+
+ out:
+	/* cleanup */
+	cfg80211_unlock_rdev(rdev);
+	dev_put(dev);
+ out_rtnl:
+	rtnl_unlock();
+
+	return err;
+ }
+
 static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
@@ -5154,6 +5303,22 @@ static struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+
+
+	{
+		.cmd = NL80211_CMD_GET_WOW,
+		.doit = nl80211_get_wow,
+		.policy = nl80211_policy,
+		/* can be retrieved by unprivileged users */
+	},
+	{
+		.cmd = NL80211_CMD_SET_WOW,
+		.doit = nl80211_set_wow,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+
+
 	{
 		.cmd = NL80211_CMD_GET_INTERFACE,
 		.doit = nl80211_get_interface,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a8c2d6b..ec066a6 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -704,7 +704,21 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 	wdev->wext.connect.ssid_len = 0;
 #endif
 
+/*
+	 * If we're not associated we cannot possibly get frames
+	 * to generate a WoW trigger. We also do this for security
+	 * purposes as with 802.11 we can roam to untrusted networks.
+	 * We require userspace to send a request to enable WoW for
+	 * each BSS.
+	 */
+	if (rdev->wow.netdev && rdev->wow.netdev == dev) {
+		rdev->wow.netdev = NULL;
+		rdev->wow.triggers_enabled = 0;
+	}
+
 	schedule_work(&cfg80211_disconnect_work);
+	
+
 }
 
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 74a9e3c..31807e2 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -84,7 +84,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
 
 	if (rdev->ops->suspend) {
 		rtnl_lock();
-		ret = rdev->ops->suspend(&rdev->wiphy);
+		ret = rdev->ops->suspend(&rdev->wiphy, &rdev->wow);
 		rtnl_unlock();
 	}
 
@@ -103,7 +103,7 @@ static int wiphy_resume(struct device *dev)
 
 	if (rdev->ops->resume) {
 		rtnl_lock();
-		ret = rdev->ops->resume(&rdev->wiphy);
+		ret = rdev->ops->resume(&rdev->wiphy, &rdev->wow);
 		rtnl_unlock();
 	}
 
-- 
1.7.0.4

