net: wireless: bcmdhd: Update to Version 5.90.195.28
authorDmitry Shmidt <dimitrysh@google.com>
Mon, 27 Feb 2012 20:35:15 +0000 (12:35 -0800)
committerDmitry Shmidt <dimitrysh@google.com>
Wed, 29 Feb 2012 18:46:07 +0000 (10:46 -0800)
- Improve scan for p2p
- Use use_rxchain support
- Use WL_WIRELESS_EXT instead of CONFIG_WIRELESS_EXT
- Initial sched_scan support

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
18 files changed:
drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/aiutils.c
drivers/net/wireless/bcmdhd/bcmsdh.c
drivers/net/wireless/bcmdhd/bcmsdh_linux.c
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
drivers/net/wireless/bcmdhd/dhd_cfg80211.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/include/linuxver.h
drivers/net/wireless/bcmdhd/include/sbchipc.h
drivers/net/wireless/bcmdhd/include/wlioctl.h
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_iw.c

index 17f07ca3a3073d547a04074866d1137d2ebcdd06..9828de6fad9d996829ba9a87f26342083aff2ac4 100644 (file)
@@ -19,7 +19,7 @@ obj-$(CONFIG_BCMDHD) += bcmdhd.o
 bcmdhd-objs += $(DHDOFILES)
 ifneq ($(CONFIG_WIRELESS_EXT),)
 bcmdhd-objs += wl_iw.o
-DHDCFLAGS += -DSOFTAP
+DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT
 endif
 ifneq ($(CONFIG_CFG80211),)
 bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
index 059df8907928e0035e87037fef1d1a031e793716..5ca0993c933318176200838228acc81f0863b85b 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $
+ * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 $
  */
 
 
index 918c8e648f1349356f843a69024d498787444397..f67b13a03a1c5c85f81347228e2f8fa2f27b651a 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $
+ * $Id: bcmsdh.c 300445 2011-12-03 05:37:20Z $
  */
 
 /**
index e01b6f8a2d4fba233de0774f3874b961ccef25f8..d257ddab84a3f8450891625dab152cff9914413a 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_linux.c 308641 2012-01-17 02:18:02Z $
+ * $Id: bcmsdh_linux.c 312788 2012-02-03 23:06:32Z $
  */
 
 /**
@@ -620,13 +620,6 @@ int bcmsdh_register_oob_intr(void * dhdp)
        return 0;
 }
 
-void *bcmsdh_get_drvdata(void)
-{
-       if (!sdhcinfo)
-               return NULL;
-       return dev_get_drvdata(sdhcinfo->dev);
-}
-
 void bcmsdh_set_irq(int flag)
 {
        if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
@@ -654,6 +647,15 @@ void bcmsdh_unregister_oob_intr(void)
 }
 #endif /* defined(OOB_INTR_ONLY) */
 
+#if defined(BCMLXSDMMC)
+void *bcmsdh_get_drvdata(void)
+{
+       if (!sdhcinfo)
+               return NULL;
+       return dev_get_drvdata(sdhcinfo->dev);
+}
+#endif
+
 /* Module parameters specific to each host-controller driver */
 
 extern uint sd_msglevel;       /* Debug message level */
index 6a8ff9431e9248fb9523a494afa54bcd7c2ed11b..b88e57a5203b495490d9ea7f93a9cf6200454f00 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $
+ * $Id: bcmsdh_sdmmc.c 314904 2012-02-14 21:36:04Z $
  */
 #include <typedefs.h>
 
@@ -35,6 +35,7 @@
 #include <sdiovar.h>   /* ioctl/iovars */
 
 #include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 
@@ -148,6 +149,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq)
        sd->sd_blockmode = TRUE;
        sd->use_client_ints = TRUE;
        sd->client_block_size[0] = 64;
+       sd->use_rxchain = FALSE;
 
        gInstance->sd = sd;
 
@@ -512,7 +514,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
        }
 
        case IOV_GVAL(IOV_RXCHAIN):
-               int_val = FALSE;
+               int_val = (int32)si->use_rxchain;
                bcopy(&int_val, arg, val_size);
                break;
 
@@ -902,8 +904,12 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
        bool fifo = (fix_inc == SDIOH_DATA_FIX);
        uint32  SGCount = 0;
        int err_ret = 0;
-
-       void *pnext;
+       void *pnext, *pprev;
+       uint ttl_len, dma_len, lft_len, xfred_len, pkt_len;
+       uint blk_num;
+       struct mmc_request mmc_req;
+       struct mmc_command mmc_cmd;
+       struct mmc_data mmc_dat;
 
        sd_trace(("%s: Enter\n", __FUNCTION__));
 
@@ -911,66 +917,148 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
        DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
        DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
 
-       /* Claim host controller */
-       sdio_claim_host(gInstance->func[func]);
-       for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
-               uint pkt_len = PKTLEN(sd->osh, pnext);
-               pkt_len += 3;
-               pkt_len &= 0xFFFFFFFC;
+       ttl_len = xfred_len = 0;
+       /* at least 4 bytes alignment of skb buff is guaranteed */
+       for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext))
+               ttl_len += PKTLEN(sd->osh, pnext);
 
-#ifdef CONFIG_MMC_MSM7X00A
-               if ((pkt_len % 64) == 32) {
-                       sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
-                       pkt_len += 32;
-               }
-#endif /* CONFIG_MMC_MSM7X00A */
-               /* Make sure the packet is aligned properly. If it isn't, then this
-                * is the fault of sdioh_request_buffer() which is supposed to give
-                * us something we can work with.
-                */
-               ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
-
-               if ((write) && (!fifo)) {
-                       err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
-                               ((uint8*)PKTDATA(sd->osh, pnext)),
-                               pkt_len);
-               } else if (write) {
-                       err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
-                               ((uint8*)PKTDATA(sd->osh, pnext)),
-                               pkt_len);
-               } else if (fifo) {
-                       err_ret = sdio_readsb(gInstance->func[func],
-                               ((uint8*)PKTDATA(sd->osh, pnext)),
-                               addr,
-                               pkt_len);
-               } else {
-                       err_ret = sdio_memcpy_fromio(gInstance->func[func],
-                               ((uint8*)PKTDATA(sd->osh, pnext)),
-                               addr,
+       if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) {
+               blk_num = 0;
+               dma_len = 0;
+       } else {
+               blk_num = ttl_len / sd->client_block_size[func];
+               dma_len = blk_num * sd->client_block_size[func];
+       }
+       lft_len = ttl_len - dma_len;
+
+       sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n",
+               __FUNCTION__, write ? "W" : "R",
+               ttl_len, func, addr, blk_num, lft_len));
+
+       if (0 != dma_len) {
+               memset(&mmc_req, 0, sizeof(struct mmc_request));
+               memset(&mmc_cmd, 0, sizeof(struct mmc_command));
+               memset(&mmc_dat, 0, sizeof(struct mmc_data));
+
+               /* Set up DMA descriptors */
+               pprev = pkt;
+               for (pnext = pkt;
+                    pnext && dma_len;
+                    pnext = PKTNEXT(sd->osh, pnext)) {
+                       pkt_len = PKTLEN(sd->osh, pnext);
+
+                       if (dma_len > pkt_len)
+                               dma_len -= pkt_len;
+                       else {
+                               pkt_len = xfred_len = dma_len;
+                               dma_len = 0;
+                               pkt = pnext;
+                       }
+
+                       sg_set_buf(&sd->sg_list[SGCount++],
+                               (uint8*)PKTDATA(sd->osh, pnext),
                                pkt_len);
-               }
 
-               if (err_ret) {
-                       sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
-                               __FUNCTION__,
-                               (write) ? "TX" : "RX",
-                               pnext, SGCount, addr, pkt_len, err_ret));
-               } else {
-                       sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
-                               __FUNCTION__,
-                               (write) ? "TX" : "RX",
-                               pnext, SGCount, addr, pkt_len));
+                       if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) {
+                               sd_err(("%s: sg list entries exceed limit\n",
+                                       __FUNCTION__));
+                               return (SDIOH_API_RC_FAIL);
+                       }
                }
 
-               if (!fifo) {
-                       addr += pkt_len;
-               }
-               SGCount ++;
+               mmc_dat.sg = sd->sg_list;
+               mmc_dat.sg_len = SGCount;
+               mmc_dat.blksz = sd->client_block_size[func];
+               mmc_dat.blocks = blk_num;
+               mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
 
+               mmc_cmd.opcode = 53;            /* SD_IO_RW_EXTENDED */
+               mmc_cmd.arg = write ? 1<<31 : 0;
+               mmc_cmd.arg |= (func & 0x7) << 28;
+               mmc_cmd.arg |= 1<<27;
+               mmc_cmd.arg |= fifo ? 0 : 1<<26;
+               mmc_cmd.arg |= (addr & 0x1FFFF) << 9;
+               mmc_cmd.arg |= blk_num & 0x1FF;
+               mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+               mmc_req.cmd = &mmc_cmd;
+               mmc_req.data = &mmc_dat;
+
+               sdio_claim_host(gInstance->func[func]);
+               mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card);
+               mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req);
+               sdio_release_host(gInstance->func[func]);
+
+               err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error;
+               if (0 != err_ret) {
+                       sd_err(("%s:CMD53 %s failed with code %d\n",
+                              __FUNCTION__,
+                              write ? "write" : "read",
+                              err_ret));
+                       sd_err(("%s:Disabling rxchain and fire it with PIO\n",
+                              __FUNCTION__));
+                       sd->use_rxchain = FALSE;
+                       pkt = pprev;
+                       lft_len = ttl_len;
+               } else if (!fifo) {
+                       addr = addr + ttl_len - lft_len - dma_len;
+               }
        }
 
-       /* Release host controller */
-       sdio_release_host(gInstance->func[func]);
+       /* PIO mode */
+       if (0 != lft_len) {
+               /* Claim host controller */
+               sdio_claim_host(gInstance->func[func]);
+               for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+                       uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) +
+                               xfred_len;
+                       pkt_len = PKTLEN(sd->osh, pnext);
+                       if (0 != xfred_len) {
+                               pkt_len -= xfred_len;
+                               xfred_len = 0;
+                       }
+                       pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
+#ifdef CONFIG_MMC_MSM7X00A
+                       if ((pkt_len % 64) == 32) {
+                               sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
+                               pkt_len += 32;
+                       }
+#endif /* CONFIG_MMC_MSM7X00A */
+
+                       if ((write) && (!fifo))
+                               err_ret = sdio_memcpy_toio(
+                                               gInstance->func[func],
+                                               addr, buf, pkt_len);
+                       else if (write)
+                               err_ret = sdio_memcpy_toio(
+                                               gInstance->func[func],
+                                               addr, buf, pkt_len);
+                       else if (fifo)
+                               err_ret = sdio_readsb(
+                                               gInstance->func[func],
+                                               buf, addr, pkt_len);
+                       else
+                               err_ret = sdio_memcpy_fromio(
+                                               gInstance->func[func],
+                                               buf, addr, pkt_len);
+
+                       if (err_ret)
+                               sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
+                                      __FUNCTION__,
+                                      (write) ? "TX" : "RX",
+                                      pnext, SGCount, addr, pkt_len, err_ret));
+                       else
+                               sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+                                       __FUNCTION__,
+                                       (write) ? "TX" : "RX",
+                                       pnext, SGCount, addr, pkt_len));
+
+                       if (!fifo)
+                               addr += pkt_len;
+                       SGCount ++;
+               }
+               sdio_release_host(gInstance->func[func]);
+       }
 
        sd_trace(("%s: Exit\n", __FUNCTION__));
        return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
@@ -1232,8 +1320,10 @@ sdioh_start(sdioh_info_t *si, int stage)
                   2.6.27. The implementation prior to that is buggy, and needs broadcom's
                   patch for it
                */
-               if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
+               if ((ret = sdio_reset_comm(gInstance->func[0]->card))) {
                        sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+                       return ret;
+               }
                else {
                        sd->num_funcs = 2;
                        sd->sd_blockmode = TRUE;
index 83f4d3df671fd56c70c3ed160f2316d99a084b71..f296dd382b5cdde4cd40f835671013bbca85414a 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc_linux.c 308645 2012-01-17 02:33:26Z $
+ * $Id: bcmsdh_sdmmc_linux.c 312783 2012-02-03 22:53:56Z $
  */
 
 #include <typedefs.h>
@@ -98,7 +98,6 @@ PBCMSDH_SDMMC_INSTANCE gInstance;
 
 extern int bcmsdh_probe(struct device *dev);
 extern int bcmsdh_remove(struct device *dev);
-
 extern volatile bool dhd_mmc_suspend;
 
 static int bcmsdh_sdmmc_probe(struct sdio_func *func,
@@ -194,8 +193,9 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev)
 
 static int bcmsdh_sdmmc_resume(struct device *pdev)
 {
+#if defined(OOB_INTR_ONLY)
        struct sdio_func *func = dev_to_sdio_func(pdev);
-
+#endif
        sd_trace(("%s Enter\n", __FUNCTION__));
        dhd_mmc_suspend = FALSE;
 #if defined(OOB_INTR_ONLY)
index 800590cca65367079f75afdd1b6094b11a9685d4..917b09b35a350520afd1a725523c59377b2a3709 100644 (file)
@@ -467,7 +467,6 @@ void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
        kfree(wl->btcoex_info);
        wl->btcoex_info = NULL;
 }
-#endif 
 
 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
 {
@@ -591,3 +590,4 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
 
        return (strlen("OK"));
 }
+#endif 
index 0c34e79bf2ca237190b304ce68390371e3e48502..597d12560c1958ac37bbac8b911e0079427b3d5a 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $
+ * $Id: dhd_linux.c 314746 2012-02-14 03:45:02Z $
  */
 
 #include <typedefs.h>
@@ -149,10 +149,10 @@ print_tainted()
 #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
 
 /* Linux wireless extension support */
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
 #include <wl_iw.h>
 extern wl_iw_extra_params_t  g_wl_iw_params;
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 #include <linux/earlysuspend.h>
@@ -212,9 +212,9 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
 
 /* Local private structure (extension of pub) */
 typedef struct dhd_info {
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
        wl_iw_t         iw;             /* wireless extensions state (must be first) */
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
        dhd_pub_t pub;
 
@@ -359,12 +359,6 @@ uint dhd_radio_up = 1;
 char iface_name[IFNAMSIZ] = {'\0'};
 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define BLOCKABLE()    (!in_atomic())
-#else
-#define BLOCKABLE()    (!in_interrupt())
-#endif
-
 /* The following are specific to the SDIO dongle */
 
 /* IOCTL response timeout */
@@ -451,9 +445,9 @@ int dhd_monitor_init(void *dhd_pub);
 int dhd_monitor_uninit(void);
 
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
 static void dhd_dpc(ulong data);
 /* forward decl */
@@ -2053,7 +2047,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
                return -1;
        }
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
        /* linux wireless extensions */
        if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
                /* may recurse, do NOT lock */
@@ -2061,7 +2055,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
                DHD_OS_WAKE_UNLOCK(&dhd->pub);
                return ret;
        }
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
        if (cmd == SIOCETHTOOL) {
@@ -2338,7 +2332,6 @@ dhd_open(struct net_device *net)
        }
 
        dhd->pub.hang_was_sent = 0;
-
 #if !defined(WL_CFG80211)
        /*
         * Force start if ifconfig_up gets called before START command
@@ -2672,7 +2665,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        dhd_monitor_init(&dhd->pub);
        dhd_state |= DHD_ATTACH_STATE_CFG80211;
 #endif
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
        /* Attach and link in the iw */
        if (!(dhd_state &  DHD_ATTACH_STATE_CFG80211)) {
                if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
@@ -2681,7 +2674,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
                }
        dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
        }
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
 
        /* Set up the watchdog timer */
@@ -2934,6 +2927,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #if defined(ARP_OFFLOAD_SUPPORT)
        int arpoe = 1;
 #endif
+#if defined(KEEP_ALIVE)
+       int res;
+#endif /* defined(KEEP_ALIVE) */
        int scan_assoc_time = DHD_SCAN_ACTIVE_TIME;
        int scan_unassoc_time = 40;
        int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
@@ -2946,14 +2942,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
        uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
 #endif
-
 #if defined(AP) || defined(WLP2P)
        uint32 apsta = 1; /* Enable APSTA mode */
 #endif /* defined(AP) || defined(WLP2P) */
 #ifdef GET_CUSTOM_MAC_ENABLE
        struct ether_addr ea_addr;
 #endif /* GET_CUSTOM_MAC_ENABLE */
-
        DHD_TRACE(("Enter %s\n", __FUNCTION__));
        dhd->op_mode = 0;
 #ifdef GET_CUSTOM_MAC_ENABLE
@@ -3083,6 +3077,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        /* Setup assoc_retry_max count to reconnect target AP in dongle */
        bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
        dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
 #if defined(AP) && !defined(WLP2P)
        /* Turn off MPC in AP mode */
        bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
@@ -3098,17 +3093,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif
 
 #if defined(KEEP_ALIVE)
-       {
        /* Set Keep Alive : be sure to use FW with -keepalive */
-       int res;
-
 #if defined(SOFTAP)
        if (ap_fw_loaded == FALSE)
 #endif
                if ((res = dhd_keep_alive_onoff(dhd)) < 0)
                        DHD_ERROR(("%s set keeplive failed %d\n",
                        __FUNCTION__, res));
-       }
 #endif /* defined(KEEP_ALIVE) */
 
        /* Read event_msgs mask */
@@ -3471,14 +3462,14 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
        net->ethtool_ops = &dhd_ethtool_ops;
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
 #if WIRELESS_EXT < 19
        net->get_wireless_stats = dhd_get_wireless_stats;
 #endif /* WIRELESS_EXT < 19 */
 #if WIRELESS_EXT > 12
        net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
 #endif /* WIRELESS_EXT > 12 */
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
        dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
 
@@ -3494,7 +3485,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
                net->dev_addr[0], net->dev_addr[1], net->dev_addr[2],
                net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]);
 
-#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211)
+#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
                wl_iw_iscan_set_scan_broadcast_prep(net, 1);
 #endif
 
@@ -3579,12 +3570,12 @@ void dhd_detach(dhd_pub_t *dhdp)
        }
 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
        if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
                /* Detatch and unlink in the iw */
                wl_iw_detach();
        }
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
        if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
                PROC_STOP(&dhd->thr_sysioc_ctl);
@@ -3748,20 +3739,20 @@ dhd_module_init(void)
        }
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
-               /*
-                * Wait till MMC sdio_register_driver callback called and made driver attach.
-                * It's needed to make sync up exit from dhd insmod  and
-                * Kernel MMC sdio device callback registration
-                */
+       /*
+        * Wait till MMC sdio_register_driver callback called and made driver attach.
+        * It's needed to make sync up exit from dhd insmod  and
+        * Kernel MMC sdio device callback registration
+        */
        if (down_timeout(&dhd_registration_sem,  msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
-               error = -EINVAL;
+               error = -ENODEV;
                DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
                goto fail_2;
                }
 #endif
 #if defined(WL_CFG80211)
        wl_android_post_init();
-#endif
+#endif /* defined(WL_CFG80211) */
 
        return error;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
@@ -4037,7 +4028,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size)
 }
 #endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
 struct iw_statistics *
 dhd_get_wireless_stats(struct net_device *dev)
 {
@@ -4055,7 +4046,7 @@ dhd_get_wireless_stats(struct net_device *dev)
        else
                return NULL;
 }
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
 
 static int
 dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
@@ -4068,7 +4059,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
        if (bcmerror != BCME_OK)
                return (bcmerror);
 
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
        if (event->bsscfgidx == 0) {
                /*
                 * Wireless ext is on primary interface only
@@ -4081,7 +4072,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
                        wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
                }
        }
-#endif /* defined(CONFIG_WIRELESS_EXT)  */
+#endif /* defined(WL_WIRELESS_EXT)  */
 
 #ifdef WL_CFG80211
        if ((ntoh32(event->event_type) == WLC_E_IF) &&
@@ -4386,6 +4377,8 @@ dhd_dev_get_pno_status(struct net_device *dev)
 
 #endif /* PNO_SUPPORT */
 
+struct work_struct work;
+
 int net_os_send_hang_message(struct net_device *dev)
 {
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4402,7 +4395,7 @@ int net_os_send_hang_message(struct net_device *dev)
                        dev_close(dev);
                        if (need_unlock)
                                rtnl_unlock();
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
                        ret = wl_iw_send_priv_event(dev, "HANG");
 #endif
 #if defined(WL_CFG80211)
@@ -4421,7 +4414,6 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
                        memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
 }
 
-
 void dhd_net_if_lock(struct net_device *dev)
 {
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
index 53eff583c3810fee3a40f0b0adfc6bfb271f019b..282a7179540b1241b185658945c304dcf4f10cac 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $
+ * $Id: dhd_sdio.c 314732 2012-02-14 03:22:42Z $
  */
 
 #include <typedefs.h>
index bea97b610a8e17b75f1114cce913a531dc2258ef..db8ea596304c955e858e46caa9fcf82a5287aca9 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc.h 277737 2011-08-16 17:54:59Z $
+ * $Id: bcmsdh_sdmmc.h 314048 2012-02-09 20:31:56Z $
  */
 
 #ifndef __BCMSDH_SDMMC_H__
@@ -82,9 +82,10 @@ struct sdioh_info {
        uint8           num_funcs;              /* Supported funcs on client */
        uint32          com_cis_ptr;
        uint32          func_cis_ptr[SDIOD_MAX_IOFUNCS];
-       uint            max_dma_len;
-       uint            max_dma_descriptors;    /* DMA Descriptors supported by this controller. */
-//     SDDMA_DESCRIPTOR        SGList[32];     /* Scatter/Gather DMA List */
+
+#define SDIOH_SDMMC_MAX_SG_ENTRIES     32
+       struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES];
+       bool            use_rxchain;
 };
 
 /************************************************************
index 53dd2f736734f0a01b1ccca422b22a5c9572d733..0e720456f5820d11e2adefc863cbc1e49fa6e50d 100644 (file)
 
 #define        EPI_RC_NUMBER           195
 
-#define        EPI_INCREMENTAL_NUMBER  23
+#define        EPI_INCREMENTAL_NUMBER  28
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             5, 90, 195, 23
+#define        EPI_VERSION             5, 90, 195, 28
 
-#define        EPI_VERSION_NUM         0x055ac317
+#define        EPI_VERSION_NUM         0x055ac31c
 
 #define EPI_VERSION_DEV                5.90.195
 
 
-#define        EPI_VERSION_STR         "5.90.195.23"
+#define        EPI_VERSION_STR         "5.90.195.28"
 
 #endif 
index d269e66f7fb89cd929b5ab02e0f64b42f2637356..54d88ee923b26536a85ba4b6cff1f4a2cb233a0d 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: linuxver.h 280266 2011-08-28 04:18:20Z $
+ * $Id: linuxver.h 312264 2012-02-02 00:49:43Z $
  */
 
 
@@ -524,6 +524,11 @@ typedef struct {
        } while (0);
 #endif /* LINUX_VERSION_CODE  */
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define BLOCKABLE()    (!in_atomic())
+#else
+#define BLOCKABLE()    (!in_interrupt())
+#endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
 #define KILL_PROC(nr, sig) \
index 3fe2a5a49d30598ff7e928021ce9e58b8ef23aac..8f757509b95ddc6216d1916f2a91127ef0860bc6 100644 (file)
@@ -5,7 +5,7 @@
  * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
  * GPIO interface, extbus, and support for serial and parallel flashes.
  *
- * $Id: sbchipc.h 277737 2011-08-16 17:54:59Z $
+ * $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
  * 
@@ -1659,6 +1659,9 @@ typedef volatile struct {
 #define CCTRL_4330_JTAG_DISABLE        0x00000008    
 
 
+#define CCTRL_43239_GPIO_SEL           0x00000002    
+#define CCTRL_43239_SDIO_HOST_WAKE     0x00000004    
+
 #define        RES4313_BB_PU_RSRC              0
 #define        RES4313_ILP_REQ_RSRC            1
 #define        RES4313_XTAL_PU_RSRC            2
index e31bfa94c006afcb9ce4a77c02bd6b9ceaf3423f..91274a0c680bc593992edc2761a1f2ff964e7d00 100644 (file)
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $
+ * $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $
  */
 
 
@@ -1213,7 +1213,7 @@ typedef struct {
 
 #define WL_AUTH_OPEN_SYSTEM     0   
 #define WL_AUTH_SHARED_KEY      1   
-#define WL_AUTH_OPEN_SHARED            3       
+#define WL_AUTH_OPEN_SHARED            2       
 
 
 #define WL_RADIO_SW_DISABLE     (1<<0)
index 2cbe333b0dd622864921d54932a841c0c3bf272d..8f6b1988180e764db4baa7753a35441d3f73c5bf 100644 (file)
@@ -223,7 +223,7 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_
        return bytes_written;
 }
 
-#ifdef PNO_SUPPORT
+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
 {
        wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
@@ -329,7 +329,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t
 exit_proc:
        return res;
 }
-#endif /* PNO_SUPPORT */
+#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */
 
 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
 {
@@ -516,7 +516,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
                char *country_code = command + strlen(CMD_COUNTRY) + 1;
                bytes_written = wldev_set_country(net, country_code);
        }
-#ifdef PNO_SUPPORT
+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
        else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
                bytes_written = dhd_dev_pno_reset(net);
        }
index 125888d028fa4a0da0e4db0bef88f383bb3dbfd7..c910fc59407b19b195e621b0aa9b8d13c72e510e 100644 (file)
@@ -202,7 +202,8 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
        struct cfg80211_pmksa *pmksa);
 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
        struct net_device *dev);
-static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted);
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+       struct net_device *ndev, bool aborted, bool fw_abort);
 /*
  * event & event Q handlers for cfg80211 interfaces
  */
@@ -236,8 +237,15 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
 static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
 static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
 /*
  * register/deregister parent device
  */
@@ -516,11 +524,11 @@ static struct ieee80211_supported_band __wl_band_2ghz = {
         * doesn't match with the IE present in the 3/4 EAPOL msg.
         */
        .ht_cap = {
-                               IEEE80211_HT_CAP_SGI_20 |
-                               IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
-                               .ht_supported = TRUE,
-                               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
-                               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+               IEEE80211_HT_CAP_SGI_20 |
+               IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+               .ht_supported = TRUE,
+               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
        }
 #endif
 };
@@ -530,7 +538,22 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
        .channels = __wl_5ghz_a_channels,
        .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
        .bitrates = wl_a_rates,
-       .n_bitrates = wl_a_rates_size
+       .n_bitrates = wl_a_rates_size,
+#if ENABLE_P2P_INTERFACE
+       /* wpa_supplicant sets wmm_enabled based on whether ht_cap
+        * is present or not. The wmm_enabled is inturn used to
+        * set the replay counters in the RSN IE. Without this
+        * the 4way handshake will fail complaining that IE in beacon
+        * doesn't match with the IE present in the 3/4 EAPOL msg.
+        */
+       .ht_cap = {
+               IEEE80211_HT_CAP_SGI_20 |
+               IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+               .ht_supported = TRUE,
+               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+       }
+#endif
 };
 
 static const u32 __wl_cipher_suites[] = {
@@ -918,8 +941,8 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
        if (wl->p2p_supported) {
                memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
                if (wl->p2p->vif_created) {
-                       if (wl_get_drv_status(wl, SCANNING, dev)) {
-                               wl_cfg80211_scan_abort(wl, dev);
+                       if (wl->scan_request) {
+                               wl_notify_escan_complete(wl, dev, true, true);
                        }
                        wldev_iovar_setint(dev, "mpc", 1);
                        wl_set_p2p_status(wl, IF_DELETING);
@@ -1088,7 +1111,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
                                rollback_lock = true;
                        }
                        WL_DBG(("ESCAN COMPLETED\n"));
-                       wl_notify_escan_complete(wl, ndev, true);
+                       wl_notify_escan_complete(wl, ndev, true, false);
                        if (rollback_lock)
                                rtnl_unlock();
                }
@@ -1508,7 +1531,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        wpa_ie_fixed_t *wps_ie;
        s32 passive_scan;
        bool iscan_req;
-       bool escan_req;
+       bool escan_req = false;
        bool p2p_ssid;
        s32 err = 0;
        s32 i;
@@ -1907,21 +1930,21 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
        switch (sme->auth_type) {
        case NL80211_AUTHTYPE_OPEN_SYSTEM:
-               val = 0;
+               val = WL_AUTH_OPEN_SYSTEM;
                WL_DBG(("open system\n"));
                break;
        case NL80211_AUTHTYPE_SHARED_KEY:
-               val = 1;
+               val = WL_AUTH_SHARED_KEY;
                WL_DBG(("shared key\n"));
                break;
        case NL80211_AUTHTYPE_AUTOMATIC:
-               val = 2;
+               val = WL_AUTH_OPEN_SHARED;
                WL_DBG(("automatic\n"));
                break;
        case NL80211_AUTHTYPE_NETWORK_EAP:
                WL_DBG(("network eap\n"));
        default:
-               val = 2;
+               val = WL_AUTH_OPEN_SHARED;
                WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
                break;
        }
@@ -2119,9 +2142,9 @@ wl_set_set_sharedkey(struct net_device *dev,
                                WL_ERR(("WLC_SET_KEY error (%d)\n", err));
                                return err;
                        }
-                       if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+                       if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
                                WL_DBG(("set auth_type to shared key\n"));
-                               val = 1;        /* shared key */
+                               val = WL_AUTH_SHARED_KEY;       /* shared key */
                                err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
                                if (unlikely(err)) {
                                        WL_ERR(("set auth failed (%d)\n", err));
@@ -2160,7 +2183,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
         * Cancel ongoing scan to sync up with sme state machine of cfg80211.
         */
        if (wl->scan_request) {
-               wl_cfg80211_scan_abort(wl, dev);
+               wl_notify_escan_complete(wl, dev, true, true);
        }
        /* Clean BSSID */
        bzero(&bssid, sizeof(bssid));
@@ -2382,7 +2405,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
                * Cancel ongoing scan to sync up with sme state machine of cfg80211.
                */
                if (wl->scan_request) {
-                       wl_cfg80211_scan_abort(wl, dev);
+                       wl_notify_escan_complete(wl, dev, true, true);
                }
                wl_set_drv_status(wl, DISCONNECTING, dev);
                scbval.val = reason_code;
@@ -2581,9 +2604,6 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
                        return -EINVAL;
                }
                swap_key_from_BE(&key);
-#if defined(CONFIG_WIRELESS_EXT)
-               dhd_wait_pend8021x(dev);
-#endif
                wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
                        wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
                if (unlikely(err)) {
@@ -2831,42 +2851,42 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                        sta->idle * 1000));
 #endif
        } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
-                       u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
-                       if (!wl_get_drv_status(wl, CONNECTED, dev) ||
-                           (dhd_is_associated(dhd, NULL) == FALSE)) {
-                               WL_ERR(("NOT assoc\n"));
-                               err = -ENODEV;
-                               goto get_station_err;
-                       }
-                       if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
-                               WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
-                                       MAC2STR(mac), MAC2STR(curmacp)));
-                       }
+               u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
+               if (!wl_get_drv_status(wl, CONNECTED, dev) ||
+                       (dhd_is_associated(dhd, NULL) == FALSE)) {
 
-                       /* Report the current tx rate */
-                       err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
-                       if (err) {
-                               WL_ERR(("Could not get rate (%d)\n", err));
-                       } else {
-                               rate = dtoh32(rate);
-                               sinfo->filled |= STATION_INFO_TX_BITRATE;
-                               sinfo->txrate.legacy = rate * 5;
-                               WL_DBG(("Rate %d Mbps\n", (rate / 2)));
-                       }
+                       WL_ERR(("NOT assoc\n"));
+                       err = -ENODEV;
+                       goto get_station_err;
+               }
+               if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+                       WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
+                               MAC2STR(mac), MAC2STR(curmacp)));
+               }
 
-                       memset(&scb_val, 0, sizeof(scb_val));
-                       scb_val.val = 0;
-                       err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
-                                       sizeof(scb_val_t), false);
-                       if (err) {
-                               WL_ERR(("Could not get rssi (%d)\n", err));
-                               goto get_station_err;
-                       }
+               /* Report the current tx rate */
+               err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+               if (err) {
+                       WL_ERR(("Could not get rate (%d)\n", err));
+               } else {
+                       rate = dtoh32(rate);
+                       sinfo->filled |= STATION_INFO_TX_BITRATE;
+                       sinfo->txrate.legacy = rate * 5;
+                       WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+               }
 
-                       rssi = dtoh32(scb_val.val);
-                       sinfo->filled |= STATION_INFO_SIGNAL;
-                       sinfo->signal = rssi;
-                       WL_DBG(("RSSI %d dBm\n", rssi));
+               memset(&scb_val, 0, sizeof(scb_val));
+               scb_val.val = 0;
+               err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+                       sizeof(scb_val_t), false);
+               if (err) {
+                       WL_ERR(("Could not get rssi (%d)\n", err));
+                       goto get_station_err;
+               }
+               rssi = dtoh32(scb_val.val);
+               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->signal = rssi;
+               WL_DBG(("RSSI %d dBm\n", rssi));
 
 get_station_err:
                if (err) {
@@ -3009,8 +3029,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
                return -EINVAL;
        }
        /* pmk list is supported only for STA interface i.e. primary interface
-         * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
-       */
+        * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+        */
        if (primary_dev != dev) {
                WL_INFO(("Not supporting Flushing pmklist on virtual"
                        " interfaces than primary interface\n"));
@@ -3173,8 +3193,21 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
        s32 params_size = 0;
        s32 err = BCME_OK;
        unsigned long flags;
+       struct net_device *dev;
 
        WL_DBG(("Enter\n"));
+       if (wl->scan_request) {
+               if (wl->scan_request->dev == wl->p2p_net)
+                       dev = wl_to_prmry_ndev(wl);
+               else
+                       dev = wl->scan_request->dev;
+       }
+       else {
+               WL_ERR(("wl->scan_request is NULL did we already do scan_abort?"
+                       "Now scan_abort for ndev %p primary %p p2p_net %p",
+                       ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+               dev = ndev;
+       }
 
        /* Our scan params only need space for 1 channel and 0 ssids */
        params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
@@ -3183,18 +3216,26 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
                err = -ENOMEM;
        } else {
                /* Do a scan abort to stop the driver's scan engine */
-               err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
+               err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
                if (err < 0) {
                        WL_ERR(("scan abort  failed \n"));
                }
        }
        del_timer_sync(&wl->scan_timeout);
        spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+       if (wl->sched_scan_req && !wl->scan_request) {
+               cfg80211_sched_scan_stopped(wl_to_wiphy(wl));
+               wl->sched_scan_req = NULL;
+       }
+#endif /* WL_SCHED_SCAN */
+
        if (wl->scan_request) {
                cfg80211_scan_done(wl->scan_request, true);
                wl->scan_request = NULL;
        }
-       wl_clr_drv_status(wl, SCANNING, ndev);
+       wl_clr_drv_status(wl, SCANNING, dev);
        spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        if (params)
                kfree(params);
@@ -3222,10 +3263,9 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
                ndev = dev;
        }
 
-       if (wl_get_drv_status(wl, SCANNING, ndev)) {
-               wl_cfg80211_scan_abort(wl, ndev);
+       if (wl->scan_request) {
+               wl_notify_escan_complete(wl, ndev, true, true);
        }
-
        target_channel = ieee80211_frequency_to_channel(channel->center_freq);
        memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
        wl->remain_on_chan_type = channel_type;
@@ -3288,7 +3328,7 @@ wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl)
                 */
                wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
                wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
-               wl_cfg80211_scan_abort(wl, dev);
+               wl_notify_escan_complete(wl, dev, true, true);
                wl_cfgp2p_discover_enable_search(wl, false);
                tx_act_frm->channel = wl->afx_hdl->peer_chan;
                wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
@@ -3442,8 +3482,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                        scb_val.val = mgmt->u.disassoc.reason_code;
                        wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
                                sizeof(scb_val_t), true);
-                       WL_DBG(("Disconnect STA : %s\n",
-                               bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf)));
+                       WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
+                               bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val));
                        cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
                        goto exit;
 
@@ -3455,7 +3495,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                        * tx is still in progress (including the dwell time),
                        * then this new action frame will not be sent out.
                        */
-                       wl_cfg80211_scan_abort(wl, dev);
+                       wl_notify_escan_complete(wl, dev, true, true);
 
                }
 
@@ -3490,6 +3530,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                ieee80211_frequency_to_channel(channel->center_freq);
 
        if (channel->band == IEEE80211_BAND_5GHZ) {
+               WL_DBG(("5GHz channel %d", af_params->channel));
                err = wldev_ioctl(dev, WLC_SET_CHANNEL,
                        &af_params->channel, sizeof(af_params->channel), true);
                if (err < 0) {
@@ -3653,7 +3694,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
 {
        s32 len = 0;
        s32 err = BCME_OK;
-       u16 auth = 0; /* d11 open authentication */
+       u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
        u32 wsec;
        u32 pval = 0;
        u32 gval = 0;
@@ -3757,7 +3798,7 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
        wpa_suite_mcast_t *mcast;
        wpa_suite_ucast_t *ucast;
        wpa_suite_auth_key_mgmt_t *mgmt;
-       u16 auth = 0; /* d11 open authentication */
+       u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
        u16 count;
        s32 err = BCME_OK;
        s32 len = 0;
@@ -4080,7 +4121,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                memcpy(beacon_ie, wps_ie, wpsie_len);
                                wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
                                beacon_ie, wpsie_len);
-                               wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
+                               wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
                                wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        } else {
@@ -4133,12 +4174,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
                                WL_DBG((" WPS IE is changed\n"));
                                kfree(wl->ap_info->wps_ie);
-                               wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
+                               wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
                                wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        } else if (wl->ap_info->wps_ie == NULL) {
                                WL_DBG((" WPS IE is added\n"));
-                               wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
+                               wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
                                wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        }
@@ -4224,6 +4265,105 @@ exit:
        return err;
 }
 
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME       30
+#define PNO_REPEAT     4
+#define PNO_FREQ_EXPO_MAX      3
+int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
+                             struct net_device *dev,
+                             struct cfg80211_sched_scan_request *request)
+{
+       ushort pno_time = PNO_TIME;
+       int pno_repeat = PNO_REPEAT;
+       int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
+       wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
+       struct wl_priv *wl = wiphy_priv(wiphy);
+       struct cfg80211_ssid *ssid = NULL;
+       int ssid_count = 0;
+       int i;
+       int ret = 0;
+
+       WL_DBG(("Enter n_match_sets:%d   n_ssids:%d \n",
+               request->n_match_sets, request->n_ssids));
+       WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+               request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+       if (wl_get_drv_status_all(wl, SCANNING)) {
+               WL_ERR(("Scanning already\n"));
+               return -EAGAIN;
+       }
+
+       if (!request || !request->n_ssids || !request->n_match_sets) {
+               WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+               return -EINVAL;
+       }
+
+       memset(&ssids_local, 0, sizeof(ssids_local));
+
+       if (request->n_match_sets > 0) {
+               for (i = 0; i < request->n_match_sets; i++) {
+                       ssid = &request->match_sets[i].ssid;
+                       memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len);
+                       ssids_local[i].SSID_len = ssid->ssid_len;
+                       WL_DBG((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
+                       ssid_count++;
+               }
+       }
+
+       if (request->n_ssids > 0) {
+               for (i = 0; i < request->n_ssids; i++) {
+                       /* Active scan req for ssids */
+                       WL_DBG((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid));
+
+                       /* match_set ssids is a supert set of n_ssid list, so we need
+                        * not add these set seperately
+                        */
+               }
+       }
+
+       if (ssid_count) {
+               if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets,
+                       pno_time, pno_repeat, pno_freq_expo_max)) < 0) {
+                       WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+                       return -EINVAL;
+               }
+
+               /* Enable the PNO */
+               if (dhd_dev_pno_enable(dev, 1) < 0) {
+                       WL_ERR(("PNO enable failed!! ret=%d \n", ret));
+                       return -EINVAL;
+               }
+               wl->sched_scan_req = request;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+       struct wl_priv *wl = wiphy_priv(wiphy);
+
+       WL_DBG(("Enter \n"));
+
+       if (dhd_dev_pno_enable(dev, 0) < 0)
+               WL_ERR(("PNO disable failed"));
+
+       if (dhd_dev_pno_reset(dev) < 0)
+               WL_ERR(("PNO reset failed"));
+
+       if (wl->scan_request && wl->sched_scan_running) {
+               wl_cfg80211_scan_abort(wl, dev);
+       }
+
+        wl->sched_scan_req = NULL;
+        wl->sched_scan_running = FALSE;
+
+       return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
 static struct cfg80211_ops wl_cfg80211_ops = {
        .add_virtual_intf = wl_cfg80211_add_virtual_iface,
        .del_virtual_intf = wl_cfg80211_del_virtual_iface,
@@ -4256,6 +4396,10 @@ static struct cfg80211_ops wl_cfg80211_ops = {
        .set_channel = wl_cfg80211_set_channel,
        .set_beacon = wl_cfg80211_add_set_beacon,
        .add_beacon = wl_cfg80211_add_set_beacon,
+#ifdef WL_SCHED_SCAN
+       .sched_scan_start = wl_cfg80211_sched_scan_start,
+       .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */
 };
 
 s32 wl_mode_to_nl80211_iftype(s32 mode)
@@ -4291,12 +4435,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
        /* Report  how many SSIDs Driver can support per Scan request */
        wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
        wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+       wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+       wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+       wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+       wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
        wdev->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION)
                | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
 
        wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
-       wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
+       /* wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - set in runtime */
        wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        wdev->wiphy->cipher_suites = __wl_cipher_suites;
        wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
@@ -4314,7 +4464,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
 #endif
                WIPHY_FLAG_4ADDR_STATION;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
-       wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+       wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
 #endif
        WL_DBG(("Registering custom regulatory)\n"));
        wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
@@ -4469,7 +4619,7 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
        u32 status =  ntoh32(e->status);
        u16 flags = ntoh16(e->flags);
 
-       WL_DBG(("event %d, status %d\n", event, status));
+       WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
        if (event == WLC_E_SET_SSID) {
                if (status == WLC_E_STATUS_SUCCESS) {
                        if (!wl_is_ibssmode(wl, ndev))
@@ -4552,7 +4702,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
        memset(body, 0, sizeof(body));
        memset(&bssid, 0, ETHER_ADDR_LEN);
-       WL_DBG(("Enter \n"));
+       WL_DBG(("Enter event %d ndev %p\n", event, ndev));
        if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
                return WL_INVALID;
 
@@ -4646,8 +4796,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
        if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
                wl_notify_connect_status_ap(wl, ndev, e, data);
        } else {
-               WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
-               ntoh32(e->event_type), ntoh32(e->status)));
+               WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+                       ntoh32(e->event_type), ntoh32(e->status), ndev));
                if (wl_is_linkup(wl, e, ndev)) {
                        wl_link_up(wl);
                        act = true;
@@ -4670,30 +4820,34 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
 
                } else if (wl_is_linkdown(wl, e)) {
                        if (wl->scan_request) {
-                               del_timer_sync(&wl->scan_timeout);
                                if (wl->escan_on) {
-                                       wl_notify_escan_complete(wl, ndev, true);
-                               } else
+                                       wl_notify_escan_complete(wl, ndev, true, true);
+                               } else {
+                                       del_timer_sync(&wl->scan_timeout);
                                        wl_iscan_aborted(wl);
+                               }
                        }
                        if (wl_get_drv_status(wl, CONNECTED, ndev)) {
                                scb_val_t scbval;
                                u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
                                printk("link down, call cfg80211_disconnected\n");
                                wl_clr_drv_status(wl, CONNECTED, ndev);
-                               /* To make sure disconnect, explictly send dissassoc
-                               *  for BSSID 00:00:00:00:00:00 issue
-                               */
-                               scbval.val = WLAN_REASON_DEAUTH_LEAVING;
-
-                               memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
-                               scbval.val = htod32(scbval.val);
-                               wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
-                                       sizeof(scb_val_t), true);
-                               cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
-                               wl_link_down(wl);
-                               wl_init_prof(wl, ndev);
-                       } else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+                               if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+                                       /* To make sure disconnect, explictly send dissassoc
+                                       *  for BSSID 00:00:00:00:00:00 issue
+                                       */
+                                       scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+                                       memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+                                       scbval.val = htod32(scbval.val);
+                                       wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+                                               sizeof(scb_val_t), true);
+                                       cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+                                       wl_link_down(wl);
+                                       wl_init_prof(wl, ndev);
+                               }
+                       }
+                       else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
                                printk("link down, during connecting\n");
                                wl_bss_connect_done(wl, ndev, e, data, false);
                        }
@@ -4704,11 +4858,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                                event, (int)ntoh32(e->status));
                        /* Clean up any pending scan request */
                        if (wl->scan_request) {
-                               del_timer_sync(&wl->scan_timeout);
                                if (wl->escan_on) {
-                                       wl_notify_escan_complete(wl, ndev, true);
-                               } else
+                                       wl_notify_escan_complete(wl, ndev, true, true);
+                               } else {
+                                       del_timer_sync(&wl->scan_timeout);
                                        wl_iscan_aborted(wl);
+                               }
                        }
                        if (wl_get_drv_status(wl, CONNECTING, ndev))
                                wl_bss_connect_done(wl, ndev, e, data, false);
@@ -4857,6 +5012,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
        u8 *curbssid;
        s32 err = 0;
        struct wiphy *wiphy;
+
        wiphy = wl_to_wiphy(wl);
 
        if (wl_is_ibssmode(wl, ndev))
@@ -4960,7 +5116,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
 
        WL_DBG((" enter\n"));
        if (wl->scan_request) {
-               wl_cfg80211_scan_abort(wl, ndev);
+               wl_notify_escan_complete(wl, ndev, true, true);
        }
        if (wl_get_drv_status(wl, CONNECTING, ndev)) {
                wl_clr_drv_status(wl, CONNECTING, ndev);
@@ -5008,6 +5164,7 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
        return 0;
 }
 
+#ifdef PNO_SUPPORT
 static s32
 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data)
@@ -5015,11 +5172,19 @@ wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
        WL_ERR((" PNO Event\n"));
 
        mutex_lock(&wl->usr_sync);
+#ifndef WL_SCHED_SCAN
        /* TODO: Use cfg80211_sched_scan_results(wiphy); */
        cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+#else
+       /* If cfg80211 scheduled scan is supported, report the pno results via sched
+        * scan results
+        */
+       wl_notify_sched_scan_results(wl, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
        mutex_unlock(&wl->usr_sync);
        return 0;
 }
+#endif /* PNO_SUPPORT */
 
 static s32
 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
@@ -5199,7 +5364,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
                 * After complete GO Negotiation, roll back to mpc mode
                 */
                if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
-               (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+                       (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
                        wldev_iovar_setint(dev, "mpc", 1);
                }
        } else {
@@ -5217,6 +5382,127 @@ exit:
        return 0;
 }
 
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "0" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 1
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data)
+{
+       wl_pfn_net_info_t *netinfo, *pnetinfo;
+       struct cfg80211_scan_request request;
+       struct wiphy *wiphy     = wl_to_wiphy(wl);
+       int err = 0;
+       struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+       struct ieee80211_channel *channel = NULL;
+       int channel_req = 0;
+       int band = 0;
+       struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+
+       WL_DBG(("Enter\n"));
+
+       if (e->event_type == WLC_E_PFN_NET_LOST) {
+               WL_DBG(("PFN NET LOST event. Do Nothing \n"));
+               return 0;
+       } else {
+               WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count));
+
+
+       if (pfn_result->count > 0) {
+               int i;
+
+               memset(&request, 0x00, sizeof(struct cfg80211_scan_request));
+               memset(&ssid, 0x00, sizeof(ssid));
+               request.wiphy = wiphy;
+
+               pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+                               - sizeof(wl_pfn_net_info_t));
+
+                       channel = (struct ieee80211_channel *)kzalloc(
+                       (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT),
+                       GFP_KERNEL);
+                       if (!channel) {
+                               WL_ERR(("No memory"));
+                               err = -ENOMEM;
+                               goto out_err;
+                       }
+
+               for (i = 0; i < pfn_result->count; i++) {
+                       netinfo = &pnetinfo[i];
+                       if (!netinfo) {
+                               WL_ERR(("Invalid netinfo ptr. index:%d", i));
+                               err = -EINVAL;
+                               goto out_err;
+                       }
+
+                       WL_DBG(("SSID:%s Channel:%d \n",
+                       netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+                       /* PFN result doesn't have all the info which are required by the supplicant
+                        * (For e.g IEs) Do a target Escan so that sched scan results are reported
+                        * via wl_inform_single_bss in the required format. Escan does require the
+                        * scan request in the form of cfg80211_scan_request. For timebeing, create
+                        * cfg80211_scan_request one out of the received PNO event.
+                        */
+                       memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID,
+                               netinfo->pfnsubnet.SSID_len);
+                       ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len;
+                       request.n_ssids++;
+
+                       channel_req = netinfo->pfnsubnet.channel;
+                       band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+                               : NL80211_BAND_2GHZ;
+                       channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+                       channel[i].band = band;
+                       channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+                       request.channels[i] = &channel[i];
+                       request.n_channels++;
+               }
+
+               /* assign parsed ssid array */
+               if (request.n_ssids)
+                       request.ssids = &ssid[0];
+
+               if (wl_get_drv_status_all(wl, SCANNING)) {
+                       /* Abort any on-going scan */
+                       wl_cfg80211_scan_abort(wl, ndev);
+               }
+
+               if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
+                       err = wl_cfgp2p_discover_enable_search(wl, false);
+                       if (unlikely(err)) {
+                               wl_clr_drv_status(wl, SCANNING, ndev);
+                               goto out_err;
+                       }
+               }
+
+               wl_set_drv_status(wl, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+               err = wl_do_escan(wl, wiphy, ndev, &request);
+#else
+               err = wl_do_escan(wl, wiphy, ndev, NULL);
+#endif
+               if (err) {
+                       wl_clr_drv_status(wl, SCANNING, ndev);
+                       goto out_err;
+               }
+       } else {
+               WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+       }
+               wl->sched_scan_running = TRUE;
+       }
+
+       kfree(channel);
+       return 0;
+
+out_err:
+       if (channel)
+               kfree(channel);
+       return err;
+}
+#endif /* WL_SCHED_SCAN */
+
 static void wl_init_conf(struct wl_conf *conf)
 {
        WL_DBG(("Enter \n"));
@@ -5257,7 +5543,9 @@ static void wl_init_event_handler(struct wl_priv *wl)
        wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
        wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
        wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
+#ifdef PNO_SUPPORT
        wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
 }
 
 static s32 wl_init_priv_mem(struct wl_priv *wl)
@@ -5559,7 +5847,7 @@ static void wl_scan_timeout(unsigned long data)
        if (wl->scan_request) {
                WL_ERR(("timer expired\n"));
                if (wl->escan_on)
-                       wl_notify_escan_complete(wl, wl->escan_info.ndev, true);
+                       wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true);
                else
                        wl_notify_iscan_complete(wl_to_iscan(wl), true);
        }
@@ -5629,23 +5917,70 @@ static struct notifier_block wl_cfg80211_netdev_notifier = {
        .notifier_call = wl_cfg80211_netdev_notifier_call,
 };
 
-static void wl_notify_escan_complete(struct wl_priv *wl,
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
        struct net_device *ndev,
-       bool aborted)
+       bool aborted, bool fw_abort)
 {
+       wl_scan_params_t *params = NULL;
+       s32 params_size = 0;
+       s32 err = BCME_OK;
        unsigned long flags;
+       struct net_device *dev;
 
        WL_DBG(("Enter \n"));
-       wl_clr_drv_status(wl, SCANNING, ndev);
-       if (p2p_is_on(wl))
-               wl_clr_p2p_status(wl, SCANNING);
 
+
+       if (wl->scan_request) {
+               if (wl->scan_request->dev == wl->p2p_net)
+                       dev = wl_to_prmry_ndev(wl);
+               else
+                       dev = wl->scan_request->dev;
+       }
+       else {
+               WL_ERR(("wl->scan_request is NULL may be internal scan."
+                       "doing scan_abort for ndev %p primary %p p2p_net %p",
+                               ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+               dev = ndev;
+       }
+       if (fw_abort) {
+               /* Our scan params only need space for 1 channel and 0 ssids */
+               params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
+               if (params == NULL) {
+                       WL_ERR(("scan params allocation failed \n"));
+                       err = -ENOMEM;
+               } else {
+                       /* Do a scan abort to stop the driver's scan engine */
+                       err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+                       if (err < 0) {
+                               WL_ERR(("scan abort  failed \n"));
+                       }
+               }
+       }
+       del_timer_sync(&wl->scan_timeout);
        spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+       if (wl->sched_scan_req && wl->sched_scan_running && !wl->scan_request) {
+               WL_DBG((" REPORTING SCHED SCAN RESULTS \n"));
+               cfg80211_sched_scan_results(wl->sched_scan_req->wiphy);
+               wl->sched_scan_running = FALSE;
+               wl->sched_scan_req = NULL;
+               wl->scan_request = NULL;
+       }
+#endif /* WL_SCHED_SCAN */
+
        if (likely(wl->scan_request)) {
                cfg80211_scan_done(wl->scan_request, aborted);
                wl->scan_request = NULL;
        }
+       if (p2p_is_on(wl))
+               wl_clr_p2p_status(wl, SCANNING);
+       wl_clr_drv_status(wl, SCANNING, dev);
        spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+       if (params)
+               kfree(params);
+
+       return err;
 }
 
 static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5769,13 +6104,12 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                        wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
                        if (wl->afx_hdl->peer_chan == WL_INVALID)
                                complete(&wl->act_frm_scan);
-               } else if (likely(wl->scan_request)) {
+               } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
                        mutex_lock(&wl->usr_sync);
-                       del_timer_sync(&wl->scan_timeout);
                        WL_INFO(("ESCAN COMPLETED\n"));
                        wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
                        wl_inform_bss(wl);
-                       wl_notify_escan_complete(wl, ndev, false);
+                       wl_notify_escan_complete(wl, ndev, false, false);
                        mutex_unlock(&wl->usr_sync);
                }
        }
@@ -5787,13 +6121,12 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                        wl_clr_p2p_status(wl, SCANNING);
                        if (wl->afx_hdl->peer_chan == WL_INVALID)
                                complete(&wl->act_frm_scan);
-               } else if (likely(wl->scan_request)) {
+               } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
                        mutex_lock(&wl->usr_sync);
-                       del_timer_sync(&wl->scan_timeout);
                        WL_INFO(("ESCAN ABORTED\n"));
                        wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
                        wl_inform_bss(wl);
-                       wl_notify_escan_complete(wl, ndev, true);
+                       wl_notify_escan_complete(wl, ndev, true, false);
                        mutex_unlock(&wl->usr_sync);
                }
        }
@@ -5806,12 +6139,11 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                        wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
                        if (wl->afx_hdl->peer_chan == WL_INVALID)
                                complete(&wl->act_frm_scan);
-               } else if (likely(wl->scan_request)) {
+               } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
                        mutex_lock(&wl->usr_sync);
-                       del_timer_sync(&wl->scan_timeout);
                        wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
                        wl_inform_bss(wl);
-                       wl_notify_escan_complete(wl, ndev, true);
+                       wl_notify_escan_complete(wl, ndev, true, false);
                        mutex_unlock(&wl->usr_sync);
                }
        }
@@ -6135,9 +6467,7 @@ static s32 wl_event_handler(void *data)
        tsk_ctl_t *tsk = (tsk_ctl_t *)data;
 
        wl = (struct wl_priv *)tsk->parent;
-
-       DAEMONIZE("wl_event_handler");
-
+       DAEMONIZE("dhd_cfg80211_event");
        complete(&tsk->completed);
 
        while (down_interruptible (&tsk->sema) == 0) {
@@ -6166,7 +6496,7 @@ static s32 wl_event_handler(void *data)
                }
                DHD_OS_WAKE_UNLOCK(wl->pub);
        }
-       WL_DBG(("%s was terminated\n", __func__));
+       WL_ERR(("%s was terminated\n", __func__));
        complete_and_exit(&tsk->completed, 0);
        return 0;
 }
@@ -6346,24 +6676,31 @@ eventmsg_out:
 s32 wl_update_wiphybands(struct wl_priv *wl)
 {
        struct wiphy *wiphy;
-       s8 phylist_buf[128];
-       s8 *phy;
+       u32 bandlist[3];
+       u32 nband = 0;
+       u32 i = 0;
        s32 err = 0;
-
-       err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
-               sizeof(phylist_buf), false);
+       WL_DBG(("Entry"));
+       memset(bandlist, 0, sizeof(bandlist));
+       err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+               sizeof(bandlist), false);
        if (unlikely(err)) {
                WL_ERR(("error (%d)\n", err));
                return err;
        }
-       phy = phylist_buf;
-       for (; *phy; phy++) {
-               if (*phy == 'a' || *phy == 'n') {
-                       wiphy = wl_to_wiphy(wl);
+       wiphy = wl_to_wiphy(wl);
+       nband = bandlist[0];
+       wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+       wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+       for (i = 1; i <= nband && i < sizeof(bandlist); i++) {
+               if (bandlist[i] == WLC_BAND_5G)
                        wiphy->bands[IEEE80211_BAND_5GHZ] =
                                &__wl_band_5ghz_a;
-               }
+               else if (bandlist[i] == WLC_BAND_2G)
+                       wiphy->bands[IEEE80211_BAND_2GHZ] =
+                               &__wl_band_2ghz;
        }
+       wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
        return err;
 }
 
@@ -6373,7 +6710,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
        struct net_device *ndev = wl_to_prmry_ndev(wl);
        struct wireless_dev *wdev = ndev->ieee80211_ptr;
 
-       WL_TRACE(("In\n"));
+       WL_DBG(("In\n"));
 
        err = dhd_config_dongle(wl, false);
        if (unlikely(err))
@@ -6401,7 +6738,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
        struct net_info *iter, *next;
        struct net_device *ndev = wl_to_prmry_ndev(wl);
 
-       WL_TRACE(("In\n"));
+       WL_DBG(("In\n"));
        /* Check if cfg80211 interface is already down */
        if (!wl_get_drv_status(wl, READY, ndev))
                return err;     /* it is even not ready */
@@ -6443,7 +6780,7 @@ s32 wl_cfg80211_up(void *para)
        struct wl_priv *wl;
        s32 err = 0;
 
-       WL_TRACE(("In\n"));
+       WL_DBG(("In\n"));
        wl = wlcfg_drv_priv;
        mutex_lock(&wl->usr_sync);
        wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
@@ -6473,7 +6810,7 @@ s32 wl_cfg80211_down(void *para)
        struct wl_priv *wl;
        s32 err = 0;
 
-       WL_TRACE(("In\n"));
+       WL_DBG(("In\n"));
        wl = wlcfg_drv_priv;
        mutex_lock(&wl->usr_sync);
        err = __wl_cfg80211_down(wl);
index 2b8e66413f23a699b4f2d6c73637d5545b40363a..435d61833f1a4d36152316aeb96aca2e3888b9ba 100644 (file)
@@ -442,6 +442,10 @@ struct wl_priv {
        bool p2p_supported;
        struct btcoex_info *btcoex_info;
        struct timer_list scan_timeout;   /* Timer for catch scan event timeout */
+#ifdef WL_SCHED_SCAN
+       struct cfg80211_sched_scan_request *sched_scan_req;     /* scheduled scan req */
+#endif /* WL_SCHED_SCAN */
+       bool sched_scan_running;        /* scheduled scan req status */
 };
 
 static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
index d09448a7932fe0dbe974c89f5374dc4804956007..e724aa3ec7256a0aca57f89beb05e677c55c8454 100644 (file)
@@ -162,11 +162,8 @@ uint wl_msg_level = WL_ERROR_VAL;
 #define htodchanspec(i) i
 #define dtohchanspec(i) i
 
-#ifdef CONFIG_WIRELESS_EXT
-
 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
 extern int dhd_wait_pend8021x(struct net_device *dev);
-#endif 
 
 #if WIRELESS_EXT < 19
 #define IW_IOCTL_IDX(cmd)      ((cmd) - SIOCIWFIRST)