diff options
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmpcispi.c | 11 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdh_linux.c | 85 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c | 2 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c | 20 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdstd.c | 21 | ||||
-rw-r--r-- | bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c | 6 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd.h | 26 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_cdc.c | 27 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_common.c | 230 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_linux.c | 270 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_proto.h | 2 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_sdio.c | 15 | ||||
-rw-r--r-- | bcm4329/src/include/epivers.h | 10 | ||||
-rw-r--r-- | bcm4329/src/include/wlioctl.h | 4 | ||||
-rw-r--r-- | bcm4329/src/wl/sys/wl_iw.c | 553 | ||||
-rw-r--r-- | bcm4329/src/wl/sys/wl_iw.h | 46 |
16 files changed, 1056 insertions, 272 deletions
diff --git a/bcm4329/src/bcmsdio/sys/bcmpcispi.c b/bcm4329/src/bcmsdio/sys/bcmpcispi.c index c0a66f1..1a8b671 100644 --- a/bcm4329/src/bcmsdio/sys/bcmpcispi.c +++ b/bcm4329/src/bcmsdio/sys/bcmpcispi.c @@ -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: bcmpcispi.c,v 1.22.2.4.4.5 2008/07/09 21:23:30 Exp $ + * $Id: bcmpcispi.c,v 1.22.2.4.4.5.6.1 2010/08/13 00:26:05 Exp $ */ #include <typedefs.h> @@ -606,18 +606,23 @@ spi_spinbits(sdioh_info_t *sd) spin_count = 0; while ((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0) { if (spin_count > SPI_SPIN_BOUND) { - ASSERT(FALSE); /* Spin bound exceeded */ + sd_err(("%s: SPIH_WFEMPTY spin bits out of bound %u times \n", + __FUNCTION__, spin_count)); + ASSERT(FALSE); } spin_count++; } - spin_count = 0; + /* Wait for SPI Transfer state machine to return to IDLE state. * The state bits are only implemented in Rev >= 5 FPGA. These * bits are hardwired to 00 for Rev < 5, so this check doesn't cause * any problems. */ + spin_count = 0; while ((SPIPCI_RREG(osh, ®s->spih_stat) & SPIH_STATE_MASK) != 0) { if (spin_count > SPI_SPIN_BOUND) { + sd_err(("%s: SPIH_STATE_MASK spin bits out of bound %u times \n", + __FUNCTION__, spin_count)); ASSERT(FALSE); } spin_count++; diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c index 0555f87..644d6be 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c @@ -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,v 1.42.10.10.2.12 2010/03/10 03:09:48 Exp $ + * $Id: bcmsdh_linux.c,v 1.42.10.10.2.14 2010/08/17 16:34:23 Exp $ */ /** @@ -75,7 +75,11 @@ struct bcmsdh_hc { bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ void *ch; unsigned int oob_irq; - unsigned long oob_flags; + unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ + bool oob_irq_registered; +#if defined(OOB_INTR_ONLY) + spinlock_t irq_lock; +#endif }; static bcmsdh_hc_t *sdhcinfo = NULL; @@ -225,6 +229,10 @@ int bcmsdh_probe(struct device *dev) sdhc->sdh = sdh; sdhc->oob_irq = irq; sdhc->oob_flags = irq_flags; + sdhc->oob_irq_registered = FALSE; /* to make sure.. */ +#if defined(OOB_INTR_ONLY) + spin_lock_init(&sdhc->irq_lock); +#endif /* chain SDIO Host Controller info together */ sdhc->next = sdhcinfo; @@ -338,7 +346,7 @@ extern uint sd_pci_slot; /* Force detection to a particular PCI */ /* slot only . Allows for having multiple */ /* WL devices at once in a PC */ /* Only one instance of dhd will be */ - /* useable at a time */ + /* usable at a time */ /* Upper word is bus number, */ /* lower word is slot number */ /* Default value of 0xFFFFffff turns this */ @@ -365,20 +373,21 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pdev->bus->number != (sd_pci_slot>>16) || PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) { SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n", - __FUNCTION__, - bcmsdh_chipmatch(pdev->vendor, pdev->device) - ? "Found compatible SDIOHC" - : "Probing unknown device", - pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, - pdev->device)); + __FUNCTION__, + bcmsdh_chipmatch(pdev->vendor, pdev->device) ? + "Found compatible SDIOHC" : + "Probing unknown device", + pdev->bus->number, PCI_SLOT(pdev->devfn), + pdev->vendor, pdev->device)); return -ENODEV; } SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n", - __FUNCTION__, - bcmsdh_chipmatch(pdev->vendor, pdev->device) - ? "Using compatible SDIOHC" - : "WARNING, forced use of unkown device", - pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device)); + __FUNCTION__, + bcmsdh_chipmatch(pdev->vendor, pdev->device) ? + "Using compatible SDIOHC" : + "WARNING, forced use of unkown device", + pdev->bus->number, PCI_SLOT(pdev->devfn), + pdev->vendor, pdev->device)); } if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) || @@ -439,7 +448,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); rc = pci_enable_device(pdev); if (rc) { - SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__)); + SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__)); goto err; } if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0), @@ -566,15 +575,34 @@ bcmsdh_unregister(void) #endif /* BCMPLATFORM_BUS */ } + + #if defined(OOB_INTR_ONLY) +void bcmsdh_oob_intr_set(bool enable) +{ + static bool curstate = 1; + unsigned long flags; + + spin_lock_irqsave(&sdhcinfo->irq_lock, flags); + if (curstate != enable) { + if (enable) + enable_irq(sdhcinfo->oob_irq); + else + disable_irq_nosync(sdhcinfo->oob_irq); + curstate = enable; + } + spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags); +} + static irqreturn_t wlan_oob_irq(int irq, void *dev_id) { dhd_pub_t *dhdp; dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev); + bcmsdh_oob_intr_set(0); + if (dhdp == NULL) { - disable_irq(sdhcinfo->oob_irq); SDLX_MSG(("Out of band GPIO interrupt fired way too early\n")); return IRQ_HANDLED; } @@ -592,14 +620,16 @@ int bcmsdh_register_oob_intr(void * dhdp) dev_set_drvdata(sdhcinfo->dev, dhdp); - /* Refer to customer Host IRQ docs about proper irqflags definition */ - error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags, - "bcmsdh_sdmmc", NULL); - - if (error) - return -ENODEV; + if (!sdhcinfo->oob_irq_registered) { + /* Refer to customer Host IRQ docs about proper irqflags definition */ + error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags, + "bcmsdh_sdmmc", NULL); + if (error) + return -ENODEV; - set_irq_wake(sdhcinfo->oob_irq, 1); + set_irq_wake(sdhcinfo->oob_irq, 1); + sdhcinfo->oob_irq_registered = TRUE; + } return 0; } @@ -611,14 +641,7 @@ void bcmsdh_unregister_oob_intr(void) set_irq_wake(sdhcinfo->oob_irq, 0); disable_irq(sdhcinfo->oob_irq); /* just in case.. */ free_irq(sdhcinfo->oob_irq, NULL); -} - -void bcmsdh_oob_intr_set(bool enable) -{ - if (enable) - enable_irq(sdhcinfo->oob_irq); - else - disable_irq(sdhcinfo->oob_irq); + sdhcinfo->oob_irq_registered = FALSE; } #endif /* defined(OOB_INTR_ONLY) */ /* Module parameters specific to each host-controller driver */ diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c index 48d3f37..5a3ca3d 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c @@ -676,6 +676,8 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) else data = 4; /* disable hw oob interrupt */ + data |= 4; /* Active HIGH */ + status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data); return status; } diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c index 196ad4f..8992a42 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c @@ -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,v 1.1.2.5.6.15 2010/04/14 21:11:46 Exp $ + * $Id: bcmsdh_sdmmc_linux.c,v 1.1.2.5.6.17 2010/08/13 00:36:19 Exp $ */ #include <typedefs.h> @@ -39,13 +39,22 @@ #if !defined(SDIO_VENDOR_ID_BROADCOM) #define SDIO_VENDOR_ID_BROADCOM 0x02d0 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ +#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ + +#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 + +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) +#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ #if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -#define SDIO_DEVICE_ID_BROADCOM_4325 0x0000 +#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ #if !defined(SDIO_DEVICE_ID_BROADCOM_4329) #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) +#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ #include <bcmsdh_sdmmc.h> @@ -116,15 +125,18 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) sd_info(("Function#: 0x%04x\n", func->num)); if (func->num == 2) { - sd_trace(("F2 found, calling bcmsdh_probe...\n")); + sd_trace(("F2 found, calling bcmsdh_remove...\n")); bcmsdh_remove(&sdmmc_dev); } } /* devices we support, null terminated */ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, { /* end: all zeroes */ }, }; diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd.c b/bcm4329/src/bcmsdio/sys/bcmsdstd.c index 0b1b575..0ca1f8f 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdstd.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdstd.c @@ -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: bcmsdstd.c,v 1.64.4.1.4.4.2.17 2010/03/10 03:09:48 Exp $ + * $Id: bcmsdstd.c,v 1.64.4.1.4.4.2.18 2010/08/17 17:00:48 Exp $ */ #include <typedefs.h> @@ -119,7 +119,7 @@ extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data); void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data) { - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16) data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data; sd_ctrl(("16: W Reg 0x%02x, Data 0x%x\n", reg, data)); } @@ -129,7 +129,7 @@ sdstd_or_reg16(sdioh_info_t *sd, uint reg, uint16 val) volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg); sd_ctrl(("16: OR Reg 0x%02x, Val 0x%x\n", reg, val)); data |= val; - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data; } static void @@ -140,7 +140,7 @@ sdstd_mod_reg16(sdioh_info_t *sd, uint reg, int16 mask, uint16 val) sd_ctrl(("16: MOD Reg 0x%02x, Mask 0x%x, Val 0x%x\n", reg, mask, val)); data &= ~mask; data |= (val & mask); - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data; } @@ -155,7 +155,7 @@ sdstd_rreg(sdioh_info_t *sd, uint reg) static inline void sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data) { - *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data; + *(volatile uint32 *)(sd->mem_space + reg) = (uint32)data; sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data)); } @@ -164,7 +164,7 @@ sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data) static inline void sdstd_wreg8(sdioh_info_t *sd, uint reg, uint8 data) { - *(volatile uint8 *)(sd->mem_space + reg) = (volatile uint8)data; + *(volatile uint8 *)(sd->mem_space + reg) = (uint8)data; sd_ctrl(("08: W Reg 0x%02x, Data 0x%x\n", reg, data)); } static uint8 @@ -287,7 +287,7 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) return SDIOH_API_RC_SUCCESS; } -/* Configure callback to client when we recieve client interrupt */ +/* Configure callback to client when we receive client interrupt */ extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) { @@ -2778,10 +2778,6 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n data++; } - /* Handle < 4 bytes. wlc_pio.c currently (as of 12/20/05) truncates buflen - * to be evenly divisable by 4. However dongle passes arbitrary lengths, - * so handle it here - */ bytes = blocksize % 4; /* If no leftover bytes, go to next block */ @@ -2898,7 +2894,8 @@ set_client_block_size(sdioh_info_t *sd, int func, int block_size) } /* Reset and re-initialize the device */ -int sdioh_sdio_reset(sdioh_info_t *si) +int +sdioh_sdio_reset(sdioh_info_t *si) { uint8 hreg; diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c index ad6d660..a8b98e2 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c @@ -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: bcmsdstd_linux.c,v 1.11.18.2 2008/05/28 18:36:56 Exp $ + * $Id: bcmsdstd_linux.c,v 1.11.18.2.16.1 2010/08/17 17:03:13 Exp $ */ #include <typedefs.h> @@ -186,7 +186,9 @@ sdstd_lock(sdioh_info_t *sd) spin_lock_irqsave(&sdos->lock, flags); if (sd->lockcount) { - sd_err(("%s: Already locked!\n", __FUNCTION__)); + sd_err(("%s: Already locked! called from %p\n", + __FUNCTION__, + __builtin_return_address(0))); ASSERT(sd->lockcount == 0); } sdstd_devintr_off(sd); diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h index 9db5c63..cc7e8cb 100644 --- a/bcm4329/src/dhd/sys/dhd.h +++ b/bcm4329/src/dhd/sys/dhd.h @@ -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: dhd.h,v 1.32.4.7.2.4.14.44 2010/06/03 21:27:48 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.49 2010/08/20 17:32:48 Exp $ */ /**************** @@ -150,8 +150,13 @@ typedef struct dhd_pub { /* Last error from dongle */ int dongle_error; - /* Suspend disable flag */ - int suspend_disable_flag; + /* Suspend disable flag and "in suspend" flag */ + int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ + int in_suspend; /* flag set to 1 when early suspend called */ +#ifdef PNO_SUPPORT + int pno_enable; /* pno status : "1" is pno enable */ +#endif /* PNO_SUPPORT */ + int dtim_skip; /* dtim skip , default 0 means wake each dtim */ /* Pkt filter defination */ char * pktfilter[100]; @@ -162,16 +167,17 @@ typedef struct dhd_pub { } dhd_pub_t; - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define _DHD_PM_RESUME_WAIT(a, b) do {\ + #define _DHD_PM_RESUME_WAIT(a, b) do { \ int retry = 0; \ + smp_mb(); \ while (dhd_mmc_suspend && retry++ != b) { \ wait_event_interruptible_timeout(a, FALSE, HZ/100); \ } \ } while (0) - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) + #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) @@ -185,7 +191,7 @@ typedef struct dhd_pub { } \ } while (0) - #else +#else #define DHD_PM_RESUME_WAIT_INIT(a) #define DHD_PM_RESUME_WAIT(a) @@ -202,7 +208,8 @@ typedef struct dhd_pub { } \ } while (0) - #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + #define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ /* Wakelock Functions */ @@ -409,9 +416,6 @@ extern char nv_path[MOD_PARAM_PATHLEN]; #define DHD_DEL_IF -0xe #define DHD_BAD_IF -0xf -#ifdef APSTA_PINGTEST -#define MAX_GUEST 8 -#endif extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); diff --git a/bcm4329/src/dhd/sys/dhd_cdc.c b/bcm4329/src/dhd/sys/dhd_cdc.c index 070e95e..61f6a6f 100644 --- a/bcm4329/src/dhd/sys/dhd_cdc.c +++ b/bcm4329/src/dhd/sys/dhd_cdc.c @@ -323,23 +323,12 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); } -#ifdef APSTA_PINGTEST -extern struct ether_addr guest_eas[MAX_GUEST]; -#endif void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) { #ifdef BDC struct bdc_header *h; -#ifdef APSTA_PINGTEST - struct ether_header *eh; - int i; -#ifdef DHD_DEBUG - char eabuf1[ETHER_ADDR_STR_LEN]; - char eabuf2[ETHER_ADDR_STR_LEN]; -#endif /* DHD_DEBUG */ -#endif /* APSTA_PINGTEST */ #endif /* BDC */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -347,9 +336,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) #ifdef BDC /* Push BDC header used to convey priority for buses that don't */ -#ifdef APSTA_PINGTEST - eh = (struct ether_header *)PKTDATA(dhd->osh, pktbuf); -#endif PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); @@ -362,19 +348,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); h->flags2 = 0; -#ifdef APSTA_PINGTEST - for (i = 0; i < MAX_GUEST; ++i) { - if (!ETHER_ISNULLADDR(eh->ether_dhost) && - bcmp(eh->ether_dhost, guest_eas[i].octet, ETHER_ADDR_LEN) == 0) { - DHD_TRACE(("send on if 1; sa %s, da %s\n", - bcm_ether_ntoa((struct ether_addr *)(eh->ether_shost), eabuf1), - bcm_ether_ntoa((struct ether_addr *)(eh->ether_dhost), eabuf2))); - /* assume all guest STAs are on interface 1 */ - h->flags2 = 1; - break; - } - } -#endif /* APSTA_PINGTEST */ h->rssi = 0; #endif /* BDC */ BDC_SET_IF_IDX(h, ifidx); diff --git a/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c index 8faffcb..e3e8dcc 100644 --- a/bcm4329/src/dhd/sys/dhd_common.c +++ b/bcm4329/src/dhd/sys/dhd_common.c @@ -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_common.c,v 1.5.6.8.2.6.6.65 2010/07/07 00:05:07 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.69 2010/08/20 00:39:21 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -50,9 +50,7 @@ int wifi_get_mac_addr(unsigned char *buf); int dhd_msg_level; -#if defined(CSCAN) #include <wl_iw.h> -#endif char fw_path[MOD_PARAM_PATHLEN]; char nv_path[MOD_PARAM_PATHLEN]; @@ -514,9 +512,6 @@ dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) return bcmerror; } -#ifdef APSTA_PINGTEST -struct ether_addr guest_eas[MAX_GUEST]; -#endif #ifdef SHOW_EVENTS static void @@ -625,16 +620,6 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_ASSOC_IND: case WLC_E_REASSOC_IND: -#ifdef APSTA_PINGTEST - { - int i; - for (i = 0; i < MAX_GUEST; ++i) - if (ETHER_ISNULLADDR(&guest_eas[i])) - break; - if (i < MAX_GUEST) - bcopy(event->addr.octet, guest_eas[i].octet, ETHER_ADDR_LEN); - } -#endif /* APSTA_PINGTEST */ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); break; @@ -655,18 +640,6 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: -#ifdef APSTA_PINGTEST - { - int i; - for (i = 0; i < MAX_GUEST; ++i) { - if (bcmp(guest_eas[i].octet, event->addr.octet, - ETHER_ADDR_LEN) == 0) { - bzero(guest_eas[i].octet, ETHER_ADDR_LEN); - break; - } - } - } -#endif /* APSTA_PINGTEST */ DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); break; @@ -972,6 +945,7 @@ void print_buf(void *pbuf, int len, int bytes_per_line) #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) +#ifdef PKT_FILTER_SUPPORT /* Convert user's input in hex pattern to byte-size mask */ static int wl_pattern_atoh(char *src, char *dst) @@ -1201,7 +1175,9 @@ fail: if (buf) MFREE(dhd->osh, buf, BUF_SIZE); } +#endif +#ifdef ARP_OFFLOAD_SUPPORT void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) { @@ -1235,6 +1211,7 @@ dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", __FUNCTION__, arp_enable)); } +#endif int dhd_preinit_ioctls(dhd_pub_t *dhd) @@ -1247,7 +1224,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint32 glom = 0; uint bcn_timeout = 3; int scan_assoc_time = 40; - int scan_unassoc_time = 80; + int scan_unassoc_time = 40; #ifdef GET_CUSTOM_MAC_ENABLE int ret; struct ether_addr ea_addr; @@ -1394,9 +1371,9 @@ dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf) iscanbuf_alloc->next = NULL; iscanbuf_head = *iscanbuf; - DHD_ISCAN(("%s: addr of allocated node = 0x%X, addr of iscanbuf_head \ - = 0x%X dhd = 0x%X\n", __FUNCTION__, iscanbuf_alloc, - iscanbuf_head, dhd)); + DHD_ISCAN(("%s: addr of allocated node = 0x%X" + "addr of iscanbuf_head = 0x%X dhd = 0x%X\n", + __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd)); if (iscanbuf_head == NULL) { *iscanbuf = iscanbuf_alloc; @@ -1557,10 +1534,10 @@ dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip) break; if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) { - DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n", \ - __FUNCTION__, l, i, bi->BSSID.octet[0], \ - bi->BSSID.octet[1], bi->BSSID.octet[2], \ - bi->BSSID.octet[3], bi->BSSID.octet[4], \ + DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n", + __FUNCTION__, l, i, bi->BSSID.octet[0], + bi->BSSID.octet[1], bi->BSSID.octet[2], + bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5])); bi_new = bi; @@ -1577,8 +1554,8 @@ dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip) for (j = i; j < results->count; j++) { if (bi && bi_new) { - DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d] \ - %X:%X:%X:%X:%X:%X\n", + DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]" + "%X:%X:%X:%X:%X:%X\n", __FUNCTION__, l, j, bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2], bi->BSSID.octet[3], bi->BSSID.octet[4], @@ -1756,15 +1733,166 @@ fail: #endif -/* Android ComboSCAN support */ +#ifdef PNO_SUPPORT +int dhd_pno_clean(dhd_pub_t *dhd) +{ + char iovbuf[128]; + int pfn_enabled = 0; + int iov_len = 0; + int ret; + + /* Disable pfn */ + iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) >= 0) { + /* clear pfn */ + iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); + if (iov_len) { + if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + } + } + else { + ret = -1; + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); + } + } + else + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + + return ret; +} + +int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) +{ + char iovbuf[128]; + int ret = -1; + + if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { + DHD_ERROR(("%s error exit\n", __FUNCTION__)); + return ret; + } + + /* Enable/disable PNO */ + if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { + if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { + DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); + return ret; + } + else { + dhd->pno_enable = pfn_enabled; + DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable)); + } + } + else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); + + return ret; +} + +/* Function to execute combined scan */ +int +dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, uchar scan_fr) +{ + int err = -1; + char iovbuf[128]; + int k, i; + wl_pfn_param_t pfn_param; + wl_pfn_t pfn_element; + + DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); + + if ((!dhd) && (!ssids_local)) { + DHD_ERROR(("%s error exit\n", __FUNCTION__)); + err = -1; + } + + /* Check for broadcast ssid */ + for (k = 0; k < nssid; k++) { + if (!ssids_local[k].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); + return err; + } + } +/* #define PNO_DUMP 1 */ +#ifdef PNO_DUMP + { + int j; + for (j = 0; j < nssid; j++) { + DHD_ERROR(("%d: scan for %s size =%d\n", j, + ssids_local[j].SSID, ssids_local[j].SSID_len)); + } + } +#endif /* PNO_DUMP */ + + /* clean up everything */ + if ((err = dhd_pno_clean(dhd)) < 0) { + DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); + return err; + } + memset(&pfn_param, 0, sizeof(pfn_param)); + memset(&pfn_element, 0, sizeof(pfn_element)); + + /* set pfn parameters */ + pfn_param.version = htod32(PFN_VERSION); + pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); + + /* set up pno scan fr */ + if (scan_fr != 0) + pfn_param.scan_freq = htod32(scan_fr); + + bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + + /* set all pfn ssid */ + for (i = 0; i < nssid; i++) { + + pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); + pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); + pfn_element.infra = htod32(1); + + memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); + pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; + + if ((err = + bcm_mkiovar("pfn_add", (char *)&pfn_element, + sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { + if ((err = + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) { + DHD_ERROR(("%s failed for i=%d error=%d\n", + __FUNCTION__, i, err)); + return err; + } + } + else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); + } + + /* Enable PNO */ + /* dhd_pno_enable(dhd, 1); */ + return err; +} + +int dhd_pno_get_status(dhd_pub_t *dhd) +{ + int ret = -1; + + if (!dhd) + return ret; + else + return (dhd->pno_enable); +} + +#endif /* PNO_SUPPORT */ + #if defined(CSCAN) +/* Androd ComboSCAN support */ /* * data parsing from ComboScan tlv list */ int -wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, \ - int input_size, int *bytes_left) +wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, + int input_size, int *bytes_left) { char* str = *list_str; uint16 short_temp; @@ -1780,8 +1908,8 @@ wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, while (*bytes_left > 0) { if (str[0] != token) { - DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", __FUNCTION__, \ - token, str[0], *bytes_left)); + DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", + __FUNCTION__, token, str[0], *bytes_left)); return -1; } @@ -1792,11 +1920,11 @@ wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, memcpy(dst, str, input_size); } else if (input_size == 2) { - memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), \ - input_size); + memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), + input_size); } else if (input_size == 4) { - memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), \ + memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), input_size); } @@ -1812,8 +1940,8 @@ wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, * channel list parsing from cscan tlv list */ int -wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \ - int channel_num, int *bytes_left) +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left) { char* str = *list_str; int idx = 0; @@ -1898,7 +2026,7 @@ wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes /* Get SSID */ if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", \ + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); return -1; } @@ -1908,8 +2036,8 @@ wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes *bytes_left -= ssid[idx].SSID_len; str += ssid[idx].SSID_len; - DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, \ - ssid[idx].SSID_len, *bytes_left)); + DHD_TRACE(("%s :size=%d left=%d\n", + (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); } else { DHD_ERROR(("### SSID size more that %d\n", str[0])); diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c index cce87ba..eb00dbd 100644 --- a/bcm4329/src/dhd/sys/dhd_linux.c +++ b/bcm4329/src/dhd/sys/dhd_linux.c @@ -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,v 1.65.4.9.2.12.2.89 2010/07/21 18:07:11 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104 2010/08/20 19:15:40 Exp $ */ #ifdef CONFIG_WIFI_CONTROL_FUNC @@ -220,9 +220,12 @@ print_tainted() #if defined(CONFIG_HAS_EARLYSUSPEND) #include <linux/earlysuspend.h> extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + +#ifdef PKT_FILTER_SUPPORT extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +#endif /* Interface control information */ typedef struct dhd_if { @@ -276,6 +279,8 @@ typedef struct dhd_info { int wl_count; int wl_packet; + int hang_was_sent; + /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -469,18 +474,22 @@ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) { - switch (action) - { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - dhd_mmc_suspend = TRUE; - return NOTIFY_OK; - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - dhd_mmc_suspend = FALSE; - return NOTIFY_OK; + int ret = NOTIFY_DONE; + + switch (action) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + dhd_mmc_suspend = TRUE; + ret = NOTIFY_OK; + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + dhd_mmc_suspend = FALSE; + ret = NOTIFY_OK; + break; } - return 0; + smp_mb(); + return ret; } static struct notifier_block dhd_sleep_pm_notifier = { @@ -491,10 +500,26 @@ extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); + /* 1 - Enable packet filter, only allow unicast packet to send up */ + /* 0 - Disable packet filter */ + if (dhd_pkt_filter_enable) { + int i; -#if defined(CONFIG_HAS_EARLYSUSPEND) + for (i = 0; i < dhd->pktfilter_count; i++) { + dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); + dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], + value, dhd_master_mode); + } + } +#endif +} -int dhd_set_suspend(int value, dhd_pub_t *dhd) +#if defined(CONFIG_HAS_EARLYSUSPEND) +static int dhd_set_suspend(int value, dhd_pub_t *dhd) { int power_mode = PM_MAX; /* wl_pkt_filter_enable_t enable_parm; */ @@ -503,28 +528,30 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd) #ifdef CUSTOMER_HW2 uint roamvar = 1; #endif /* CUSTOMER_HW2 */ - int i; -#define htod32(i) i + DHD_TRACE(("%s: enter, value = %d in_suspend = %d\n", + __FUNCTION__, value, dhd->in_suspend)); - if (dhd && (dhd->up && !dhd->suspend_disable_flag)) { - dhd_os_proto_block(dhd); - if (value) { + if (dhd && dhd->up) { + if (value && dhd->in_suspend) { /* Kernel suspended */ + DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); /* Enable packet filter, only allow unicast packet to send up */ - if (dhd_pkt_filter_enable) { - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 1, dhd_master_mode); - } - } - - /* set bcn_li_dtim */ + dhd_set_packet_filter(1, dhd); + + /* if dtim skip setup as default force it to wake each thrid dtim + * for better power saving. + * Note that side effect is chance to miss BC/MC packet + */ + if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) + bcn_li_dtim = 3; + else + bcn_li_dtim = dhd->dtim_skip; bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); @@ -536,54 +563,63 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd) } else { /* Kernel resumed */ + DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + power_mode = PM_FAST; dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); /* disable pkt filter */ - if (dhd_pkt_filter_enable) { - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } - } + dhd_set_packet_filter(0, dhd); - /* set bcn_li_dtim */ - bcn_li_dtim = 0; - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + /* restore pre-suspend setting for dtim_skip */ + bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, + 4, iovbuf, sizeof(iovbuf)); + + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #ifdef CUSTOMER_HW2 roamvar = 0; bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #endif /* CUSTOMER_HW2 */ } - dhd_os_proto_unblock(dhd); } return 0; } +static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) +{ + dhd_pub_t *dhdp = &dhd->pub; + + dhd_os_wake_lock(dhdp); + dhd_os_proto_block(dhdp); + /* Set flag when early suspend was called */ + dhdp->in_suspend = val; + if (!dhdp->suspend_disable_flag) + dhd_set_suspend(val, dhdp); + dhd_os_proto_unblock(dhdp); + dhd_os_wake_unlock(dhdp); +} + static void dhd_early_suspend(struct early_suspend *h) { - struct dhd_info *dhdp; - dhdp = container_of(h, struct dhd_info, early_suspend); + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); DHD_TRACE(("%s: enter\n", __FUNCTION__)); - dhd_set_suspend(1, &dhdp->pub); + if (dhd) + dhd_suspend_resume_helper(dhd, 1); } static void dhd_late_resume(struct early_suspend *h) { - struct dhd_info *dhdp; - dhdp = container_of(h, struct dhd_info, early_suspend); + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); DHD_TRACE(("%s: enter\n", __FUNCTION__)); - dhd_set_suspend(0, &dhdp->pub); + if (dhd) + dhd_suspend_resume_helper(dhd, 0); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ @@ -1092,7 +1128,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) /* Send Event when bus down detected during data session */ if (dhd->pub.busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); - wl_iw_send_priv_event(net, "HANG"); + net_os_send_hang_message(net); } dhd_os_wake_unlock(&dhd->pub); return -ENODEV; @@ -1785,7 +1821,7 @@ done: if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && (!dhd->pub.dongle_reset))) { DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); - wl_iw_send_priv_event(net, "HANG"); + net_os_send_hang_message(net); } if (!bcmerror && buf && ioc.buf) { @@ -2175,6 +2211,12 @@ dhd_bus_start(dhd_pub_t *dhdp) setbit(dhdp->eventmask, WLC_E_TXFAIL); setbit(dhdp->eventmask, WLC_E_JOIN_START); setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE); +#ifdef PNO_SUPPORT + setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND); +#endif /* PNO_SUPPORT */ + +/* enable dongle roaming event */ + setbit(dhdp->eventmask, WLC_E_ROAM); dhdp->pktfilter_count = 1; /* Setup filter to allow only unicast */ @@ -2305,7 +2347,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2], dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); -#if defined(CONFIG_WIRELESS_EXT) && !defined(CSCAN) +#if defined(CONFIG_WIRELESS_EXT) #ifdef SOFTAP if (ifidx == 0) /* Don't call for SOFTAP Interface in SOFTAP MODE */ @@ -2369,7 +2411,8 @@ dhd_detach(dhd_pub_t *dhdp) int i; #if defined(CONFIG_HAS_EARLYSUSPEND) - unregister_early_suspend(&dhd->early_suspend); + if (dhd->early_suspend.suspend) + unregister_early_suspend(&dhd->early_suspend); #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ #if defined(CONFIG_WIRELESS_EXT) /* Attach and link in the iw */ @@ -2576,14 +2619,17 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) int timeout = dhd_ioctl_timeout_msec; /* Convert timeout in millsecond to jiffies */ - timeout = timeout * HZ / 1000; + /* timeout = timeout * HZ / 1000; */ + timeout = msecs_to_jiffies(timeout); /* Wait until control frame is available */ add_wait_queue(&dhd->ioctl_resp_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - - while (!(*condition) && (!signal_pending(current) && timeout)) + smp_mb(); + while (!(*condition) && (!signal_pending(current) && timeout)) { timeout = schedule_timeout(timeout); + smp_mb(); + } if (signal_pending(current)) *pending = TRUE; @@ -2849,12 +2895,70 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) /* Turning on watchdog back */ if (!flag) dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); return 1; } +int net_os_set_suspend_disable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + ret = dhd->pub.suspend_disable_flag; + dhd->pub.suspend_disable_flag = val; + } + return ret; +} + +int net_os_set_suspend(struct net_device *dev, int val) +{ + int ret = 0; +#if defined(CONFIG_HAS_EARLYSUSPEND) + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) { + dhd_os_proto_block(&dhd->pub); + ret = dhd_set_suspend(val, &dhd->pub); + dhd_os_proto_unblock(&dhd->pub); + } +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + return ret; +} + +int net_os_set_dtim_skip(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) + dhd->pub.dtim_skip = val; + + return 0; +} + +int net_os_set_packet_filter(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + /* Packet filtering is set only if we still in early-suspend and + * we need either to turn it ON or turn it OFF + * We can always turn it OFF in case of early-suspend, but we turn it + * back ON only if suspend_disable_flag was not set + */ + if (dhd && dhd->pub.up) { + dhd_os_proto_block(&dhd->pub); + if (dhd->pub.in_suspend) { + if (!val || (val && !dhd->pub.suspend_disable_flag)) + dhd_set_packet_filter(val, &dhd->pub); + } + dhd_os_proto_unblock(&dhd->pub); + } + return ret; +} + + void dhd_dev_init_ioctl(struct net_device *dev) { @@ -2863,6 +2967,47 @@ dhd_dev_init_ioctl(struct net_device *dev) dhd_preinit_ioctls(&dhd->pub); } +#ifdef PNO_SUPPORT +/* Linux wrapper to call common dhd_pno_clean */ +int +dhd_dev_pno_reset(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_clean(&dhd->pub)); +} + + +/* Linux wrapper to call common dhd_pno_enable */ +int +dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_enable(&dhd->pub, pfn_enabled)); +} + + +/* Linux wrapper to call common dhd_pno_set */ +int +dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, uchar scan_fr) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr)); +} + +/* Linux wrapper to get pno status */ +int +dhd_dev_get_pno_status(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_get_status(&dhd->pub)); +} + +#endif /* PNO_SUPPORT */ + static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd) { @@ -3045,11 +3190,16 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } -int net_os_set_suspend_disable(struct net_device *dev, int val) +int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; - if (dhd) - dhd->pub.suspend_disable_flag = val; - return 0; + if (dhd) { + if (!dhd->hang_was_sent) { + dhd->hang_was_sent = 1; + ret = wl_iw_send_priv_event(dev, "HANG"); + } + } + return ret; } diff --git a/bcm4329/src/dhd/sys/dhd_proto.h b/bcm4329/src/dhd/sys/dhd_proto.h index 382785a..7ef6929 100644 --- a/bcm4329/src/dhd/sys/dhd_proto.h +++ b/bcm4329/src/dhd/sys/dhd_proto.h @@ -34,7 +34,7 @@ #include <wlioctl.h> #ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */ +#define IOCTL_RESP_TIMEOUT 3000 /* In milli second */ #endif #ifndef IOCTL_CHIP_ACTIVE_TIMEOUT diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c index 0cf6508..7b54f60 100644 --- a/bcm4329/src/dhd/sys/dhd_sdio.c +++ b/bcm4329/src/dhd/sys/dhd_sdio.c @@ -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,v 1.157.2.27.2.33.2.126 2010/06/15 23:38:39 Exp $ + * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.129 2010/08/19 20:36:22 Exp $ */ #include <typedefs.h> @@ -124,11 +124,11 @@ /* Bump up limit on waiting for HT to account for first startup; * if the image is doing a CRC calculation before programming the PMU * for HT availability, it could take a couple hundred ms more, so - * max out at a half second (500000us). + * max out at a 1 second (1000000us). */ -#if (PMU_MAX_TRANSITION_DLY <= 500000) +#if (PMU_MAX_TRANSITION_DLY < 1000000) #undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 500000 +#define PMU_MAX_TRANSITION_DLY 1000000 #endif /* Value for ChipClockCSR during initial setup */ @@ -4218,6 +4218,11 @@ dhdsdio_dpc(dhd_bus_t *bus) bus->intstatus = intstatus; clkwait: + +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(1); +#endif + /* Re-enable interrupts to detect new device events (mailbox, rx frame) * or clock availability. (Allows tx loop to check ipend if desired.) * (Unless register access seems hosed, as we may not be able to ACK...) @@ -4694,8 +4699,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) bus->idlecount = 0; if (bus->activity) { bus->activity = FALSE; - dhd_os_wd_timer(bus->dhd,dhd_watchdog_ms); - } else { dhdsdio_clkctl(bus, CLK_NONE, FALSE); } } diff --git a/bcm4329/src/include/epivers.h b/bcm4329/src/include/epivers.h index 733b133..caceabd 100644 --- a/bcm4329/src/include/epivers.h +++ b/bcm4329/src/include/epivers.h @@ -31,18 +31,18 @@ #define EPI_MINOR_VERSION 218 -#define EPI_RC_NUMBER 246 +#define EPI_RC_NUMBER 248 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 246, 0 +#define EPI_VERSION 4, 218, 248, 0 -#define EPI_VERSION_NUM 0x04daf600 +#define EPI_VERSION_NUM 0x04daf800 -#define EPI_VERSION_STR "4.218.246.0" -#define EPI_ROUTER_VERSION_STR "4.219.246.0" +#define EPI_VERSION_STR "4.218.248.0" +#define EPI_ROUTER_VERSION_STR "4.219.248.0" #endif diff --git a/bcm4329/src/include/wlioctl.h b/bcm4329/src/include/wlioctl.h index d346945..345ba34 100644 --- a/bcm4329/src/include/wlioctl.h +++ b/bcm4329/src/include/wlioctl.h @@ -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,v 1.601.4.15.2.14.2.61 2010/05/04 20:26:25 Exp $ + * $Id: wlioctl.h,v 1.601.4.15.2.14.2.62 2010/08/19 01:20:12 Exp $ */ @@ -1317,6 +1317,8 @@ enum { #define PFN_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + typedef struct wl_pfn_param { int32 version; diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c index 0307ae0..c6b2e8a 100644 --- a/bcm4329/src/wl/sys/wl_iw.c +++ b/bcm4329/src/wl/sys/wl_iw.c @@ -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: wl_iw.c,v 1.51.4.9.2.6.4.124 2010/07/27 20:46:02 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142 2010/08/20 19:12:47 Exp $ */ @@ -109,6 +109,7 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev); } while (0) static int g_onoff = G_WLAN_SET_ON; +wl_iw_extra_params_t g_wl_iw_params; static struct mutex wl_start_lock; static struct mutex wl_cache_lock; @@ -667,14 +668,20 @@ wl_iw_set_power_mode( dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)); dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); - } - else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { + + /* Disable packet filtering if necessary */ + net_os_set_packet_filter(dev, 0); + + } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); - } - else { + + /* Enable packet filtering if was turned off */ + net_os_set_packet_filter(dev, 1); + + } else { WL_ERROR(("Unkwown yet power setting, ignored\n")); } @@ -849,9 +856,25 @@ wl_iw_set_suspend( ) { int suspend_flag; + int ret_now; + int ret = 0; - suspend_flag = *(extra + strlen("SETSUSPEND") + 1) - '0'; - return net_os_set_suspend_disable(dev, suspend_flag); + suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now))) + WL_ERROR(("%s: Suspend Flag %d -> %d\n", \ + __FUNCTION__, ret_now, suspend_flag)); + else + WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } + + return ret; } int @@ -890,7 +913,7 @@ wl_iw_get_link_speed( char *p = extra; static int link_speed; - + net_os_wake_lock(dev); if (g_onoff == G_WLAN_SET_ON) { error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed)); link_speed *= 500000; @@ -900,6 +923,91 @@ wl_iw_get_link_speed( wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_get_dtim_skip( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + char iovbuf[32]; + + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { + + memset(iovbuf, 0, sizeof(iovbuf)); + strcpy(iovbuf, "bcn_li_dtim"); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR, + &iovbuf, sizeof(iovbuf))) >= 0) { + + p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]); + WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0])); + wrqu->data.length = p - extra + 1; + } + else + WL_ERROR(("%s: get dtim_skip failed code %d\n", \ + __FUNCTION__, error)); + } + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_set_dtim_skip( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + int bcn_li_dtim; + char iovbuf[32]; + + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { + + bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0'); + + if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) { + + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR, + &iovbuf, sizeof(iovbuf))) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + + net_os_set_dtim_skip(dev, bcn_li_dtim); + + WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, \ + bcn_li_dtim)); + goto exit; + } + else WL_ERROR(("%s: set dtim_skip %d failed code %d\n", \ + __FUNCTION__, bcn_li_dtim, error)); + } + else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", \ + __FUNCTION__, bcn_li_dtim)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } @@ -916,6 +1024,8 @@ wl_iw_get_band( char *p = extra; static int band; + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band)); @@ -923,6 +1033,8 @@ wl_iw_get_band( wrqu->data.length = p - extra + 1; } + + net_os_wake_unlock(dev); return error; } @@ -939,9 +1051,11 @@ wl_iw_set_band( char *p = extra; uint band; + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { - band = *(extra + strlen(BAND_SET_CMD) + 1) - '0'; + band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0'); if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { @@ -952,20 +1066,212 @@ wl_iw_set_band( WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band)); goto exit; } - else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \ + else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \ band, error)); } - else WL_ERROR(("%s Incorrect band setting, ignored\n", __FUNCTION__)); + else WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + +#ifdef PNO_SUPPORT + +static int +wl_iw_set_pno_reset( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + + net_os_wake_lock(dev); + if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { + + if ((error = dhd_dev_pno_reset(dev)) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set OK\n", __FUNCTION__)); + goto exit; + } + else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + + + +static int +wl_iw_set_pno_enable( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + int pfn_enabled; + + net_os_wake_lock(dev); + pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0'); + + if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { + + if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set OK\n", __FUNCTION__)); + goto exit; + } + else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); } p += snprintf(p, MAX_WX_STRING, "FAIL"); exit: wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } + +static int +wl_iw_set_pno_set( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int res = -1; + wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + int nssid = 0; + cmd_tlv_t *cmd_tlv_temp; + char type; + char *str_ptr; + int tlv_size_left; + int pno_time; + +#ifdef PNO_SET_DEBUG + int i; + char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \ + 'S', 0x01, 0x00, 0x00, + 'S', + 0x04, + 'B', 'R', 'C', 'M', + 'S', + 0x04, + 'G', 'O', 'O', 'G', + 'T', + 0x0A, + }; +#endif + + net_os_wake_lock(dev); + WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + goto exit_proc; + } + + if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) { + WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \ + wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))); + goto exit_proc; + } + +#ifdef PNO_SET_DEBUG + if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) { + res = -ENOMEM; + goto exit_proc; + } + memcpy(extra, pno_in_example, sizeof(pno_in_example)); + wrqu->data.length = sizeof(pno_in_example); + for (i = 0; i < wrqu->data.length; i++) + printf("%02X ", extra[i]); + printf("\n"); +#endif + + str_ptr = extra; +#ifdef PNO_SET_DEBUG + str_ptr += strlen("PNOSETUP "); + tlv_size_left = wrqu->data.length - strlen("PNOSETUP "); +#else + str_ptr += strlen(PNOSETUP_SET_CMD); + tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD); +#endif + + cmd_tlv_temp = (cmd_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \ + (cmd_tlv_temp->version == PNO_TLV_VERSION) && \ + (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) + { + str_ptr += sizeof(cmd_tlv_t); + tlv_size_left -= sizeof(cmd_tlv_t); + + if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \ + MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { + WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } + else { + while (tlv_size_left > 0) + { + type = str_ptr[0]; + switch (type) { + case PNO_TLV_TYPE_TIME: + + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &pno_time, \ + sizeof(pno_time), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_proc; + } + break; + + default: + WL_ERROR(("%s get unkwown type %X\n", \ + __FUNCTION__, type)); + goto exit_proc; + break; + } + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time); + +exit_proc: + net_os_wake_unlock(dev); + return res; +} +#endif + static int wl_iw_get_rssi( struct net_device *dev, @@ -981,12 +1287,15 @@ wl_iw_get_rssi( static char ssidbuf[SSID_FMT_BUF_LEN]; scb_val_t scb_val; + net_os_wake_lock(dev); + bzero(&scb_val, sizeof(scb_val_t)); if (g_onoff == G_WLAN_SET_ON) { error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); if (error) { WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error)); + net_os_wake_unlock(dev); return error; } rssi = dtoh32(scb_val.val); @@ -1001,6 +1310,7 @@ wl_iw_get_rssi( p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } @@ -1112,6 +1422,8 @@ wl_iw_control_wl_off( sdioh_stop(NULL); #endif + net_os_set_dtim_skip(dev, 0); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); wl_iw_send_priv_event(dev, "STOP"); @@ -1138,7 +1450,6 @@ wl_iw_control_wl_on( wl_iw_send_priv_event(dev, "START"); -#if !defined(CSCAN) #ifdef SOFTAP if (!ap_fw_loaded) { wl_iw_iscan_set_scan_broadcast_prep(dev, 0); @@ -1146,7 +1457,6 @@ wl_iw_control_wl_on( #else wl_iw_iscan_set_scan_broadcast_prep(dev, 0); #endif -#endif WL_TRACE(("Exited %s \n", __FUNCTION__)); @@ -1559,6 +1869,7 @@ wl_iw_set_freq( if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) return error; + g_wl_iw_params.target_channel = chan; return -EINPROGRESS; } @@ -1579,7 +1890,6 @@ wl_iw_get_freq( if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; - fwrq->m = dtoh32(ci.hw_channel); fwrq->e = dtoh32(0); return 0; @@ -1907,6 +2217,41 @@ wl_iw_get_spy( return 0; } + +static int +wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size) +{ + chanspec_t chanspec = 0; + + if (ch != 0) { + + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0]) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + htodchanspec(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); + + WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", \ + __FUNCTION__, join_params->params.chanspec_list[0])); + } + return 1; +} + static int wl_iw_set_wap( struct net_device *dev, @@ -1917,6 +2262,7 @@ wl_iw_set_wap( { int error = -EINVAL; wl_join_params_t join_params; + int join_params_size; WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); @@ -1938,16 +2284,26 @@ wl_iw_set_wap( memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN); - if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params)))) { - WL_ERROR(("Invalid ioctl data.\n")); + WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel)); + wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { + WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error)); return error; } + if (g_ssid.SSID_len) { + WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \ + g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \ + g_wl_iw_params.target_channel)); + } + memset(&g_ssid, 0, sizeof(g_ssid)); return 0; @@ -2244,6 +2600,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) wl_iscan_results_t list; wl_scan_results_t *results; uint32 status; + int res; mutex_lock(&wl_cache_lock); if (iscan->list_cur) { @@ -2278,20 +2635,25 @@ wl_iw_iscan_get(iscan_info_t *iscan) memset(&list, 0, sizeof(list)); list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); - (void) dev_iw_iovar_getbuf( + res = dev_iw_iovar_getbuf( iscan->dev, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, buf->iscan_buf, WLC_IW_ISCAN_MAXLEN); - results->buflen = dtoh32(results->buflen); - results->version = dtoh32(results->version); - results->count = dtoh32(results->count); - WL_SCAN(("results->count = %d\n", results->count)); - - WL_SCAN(("results->buflen = %d\n", results->buflen)); - status = dtoh32(list_buf->status); + if (res == 0) { + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + results->count = dtoh32(results->count); + WL_SCAN(("results->count = %d\n", results->count)); + + WL_SCAN(("results->buflen = %d\n", results->buflen)); + status = dtoh32(list_buf->status); + } else { + WL_ERROR(("%s returns error %d\n", __FUNCTION__, res)); + status = WL_SCAN_RESULTS_NO_MEM; + } mutex_unlock(&wl_cache_lock); return status; } @@ -2316,10 +2678,8 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); -#if !defined(CSCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; -#endif WL_TRACE(("Send Event ISCAN complete\n")); #endif } @@ -2591,6 +2951,8 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) } leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); if (!leaf) { + WL_ERROR(("Memory alloc failure %d\n", \ + bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)); mutex_unlock(&wl_cache_lock); return -ENOMEM; } @@ -2739,7 +3101,7 @@ wl_iw_set_scan( if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) { WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error)); - g_scan_specified_ssid = 0; /* Clean to allow future ISCAN */ + g_scan_specified_ssid = 0; return -EBUSY; } @@ -2753,7 +3115,6 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; -#if !defined(CSCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) { g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED; WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__)); @@ -2762,7 +3123,6 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); return 0; } -#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (flag) @@ -2794,6 +3154,7 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) return 0; } + static int wl_iw_iscan_set_scan( struct net_device *dev, @@ -2804,6 +3165,7 @@ wl_iw_iscan_set_scan( { wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; + int ret = 0; WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); @@ -2812,28 +3174,38 @@ wl_iw_iscan_set_scan( return -EINVAL; #endif + net_os_wake_lock(dev); + #if defined(SOFTAP) if (ap_cfg_running) { WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); - return 0; + goto set_scan_end; } #endif if (g_onoff == G_WLAN_SET_OFF) { WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); - return 0; + goto set_scan_end; } +#ifdef PNO_SUPPORT + if (dhd_dev_get_pno_status(dev)) { + WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); + } +#endif + if ((!iscan) || (iscan->sysioc_pid < 0)) { WL_TRACE(("%s use backup if iscan thread is not successful\n", \ __FUNCTION__)); - return wl_iw_set_scan(dev, info, wrqu, extra); + ret = wl_iw_set_scan(dev, info, wrqu, extra); + goto set_scan_end; } if (g_scan_specified_ssid) { WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \ __FUNCTION__)); - return EBUSY; + ret = EBUSY; + goto set_scan_end; } memset(&ssid, 0, sizeof(ssid)); @@ -2848,7 +3220,8 @@ wl_iw_iscan_set_scan( if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { WL_TRACE(("%s First ISCAN in progress : ignoring SC = %s\n", \ __FUNCTION__, req->essid)); - return -EBUSY; + ret = -EBUSY; + goto set_scan_end; } #endif ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); @@ -2856,14 +3229,15 @@ wl_iw_iscan_set_scan( ssid.SSID_len = htod32(ssid.SSID_len); dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as)); wl_iw_set_event_mask(dev); - return wl_iw_set_scan(dev, info, wrqu, extra); + ret = wl_iw_set_scan(dev, info, wrqu, extra); + goto set_scan_end; } else { g_scan_specified_ssid = 0; if (iscan->iscan_state == ISCAN_STATE_SCANING) { WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__)); - return 0; + goto set_scan_end; } } } @@ -2871,7 +3245,9 @@ wl_iw_iscan_set_scan( wl_iw_iscan_set_scan_broadcast_prep(dev, 0); - return 0; +set_scan_end: + net_os_wake_unlock(dev); + return ret; } #endif @@ -3314,6 +3690,7 @@ wl_iw_iscan_get_scan( iscan_info_t *iscan = g_iscan; iscan_buf_t * p_buf; uint32 counter = 0; + uint8 channel; #if !defined(CSCAN) __u16 merged_len = 0; uint buflen_from_user = dwrq->length; @@ -3333,14 +3710,12 @@ wl_iw_iscan_get_scan( return -EINVAL; } -#if !defined(CSCAN) if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \ dev->name, __FUNCTION__)); return -EAGAIN; } -#endif - + if ((!iscan) || (iscan->sysioc_pid < 0)) { WL_TRACE(("%ssysioc_pid\n", __FUNCTION__)); return wl_iw_get_scan(dev, info, dwrq, extra); @@ -3417,8 +3792,9 @@ wl_iw_iscan_get_scan( iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), - CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + iwe.u.freq.m = wf_channel2mhz(channel, + channel <= CH_MAX_2G_CHANNEL ? WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); @@ -3470,9 +3846,8 @@ wl_iw_iscan_get_scan( dwrq->length += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); - +#endif /* CSCAN */ g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; -#endif WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); @@ -3492,6 +3867,8 @@ wl_iw_set_essid( ) { int error; + wl_join_params_t join_params; + int join_params_size; WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); @@ -3512,11 +3889,24 @@ wl_iw_set_essid( g_ssid.SSID_len = 0; } g_ssid.SSID_len = htod32(g_ssid.SSID_len); - if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &g_ssid, sizeof(g_ssid)))) + + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); + join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); + memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + + wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { + WL_ERROR(("Invalid ioctl data=%d\n", error)); return error; + } if (g_ssid.SSID_len) { - WL_TRACE(("%s: join SSID=%s\n", __FUNCTION__, g_ssid.SSID)); + WL_TRACE(("%s: join SSID=%s ch=%d\n", __FUNCTION__, \ + g_ssid.SSID, g_wl_iw_params.target_channel)); } return 0; } @@ -3544,7 +3934,6 @@ wl_iw_get_essid( ssid.SSID_len = dtoh32(ssid.SSID_len); - memcpy(extra, ssid.SSID, ssid.SSID_len); dwrq->length = ssid.SSID_len; @@ -3569,7 +3958,6 @@ wl_iw_set_nick( if (!extra) return -EINVAL; - if (dwrq->length > sizeof(iw->nickname)) return -E2BIG; @@ -4945,8 +5333,15 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) { WL_ERROR(("%s error exit\n", __FUNCTION__)); err = -1; + goto exit; } +#ifdef PNO_SUPPORT + if (dhd_dev_get_pno_status(dev)) { + WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); + } +#endif + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); if (nssid > 0) { @@ -5115,7 +5510,6 @@ static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \ &iscan->iscan_ex_params_p->params.scan_type, 1); - res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); } else { @@ -5171,16 +5565,18 @@ wl_iw_set_cscan( __FUNCTION__, info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length)); + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_OFF) { WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); - return -1; + goto exit_proc; } if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) { WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \ wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))); - return -1; + goto exit_proc; } #ifdef TLV_DEBUG @@ -5301,10 +5697,16 @@ wl_iw_set_cscan( goto exit_proc; } - + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + WL_ERROR(("%s First ISCAN in progress : ignoring\n", __FUNCTION__)); + res = -EBUSY; + goto exit_proc; + } + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); exit_proc: + net_os_wake_unlock(dev); return res; } @@ -6275,6 +6677,20 @@ static int wl_iw_set_priv( ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0) + ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) + ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) + ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); +#if defined(PNO_SUPPORT) + else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) + ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) + ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) + ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); +#endif #if defined(CSCAN) else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra); @@ -6290,8 +6706,6 @@ static int wl_iw_set_priv( #endif else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0) ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "SETSUSPEND", strlen("SETSUSPEND")) == 0) - ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); #ifdef SOFTAP else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) { wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra); @@ -6859,20 +7273,29 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) WL_SOFTAP(("STA connect received %d\n", event_type)); if (ap_cfg_running) { wl_iw_send_priv_event(priv_dev, "STA_JOIN"); - goto wl_iw_event_end; + goto wl_iw_event_end; } #endif memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; cmd = IWEVREGISTERED; break; + case WLC_E_ROAM: + if (status != WLC_E_STATUS_SUCCESS) { + WL_ERROR(("ROAMING did not succeeded, keep status Quo\n")); + goto wl_iw_event_end; + } + memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + cmd = SIOCGIWAP; + break; case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: #if defined(SOFTAP) WL_SOFTAP(("STA disconnect received %d\n", event_type)); if (ap_cfg_running) { wl_iw_send_priv_event(priv_dev, "STA_LEAVE"); - goto wl_iw_event_end; + goto wl_iw_event_end; } #endif cmd = SIOCGIWAP; @@ -7016,6 +7439,20 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) #endif break; + case WLC_E_PFN_NET_FOUND: + { + wlc_ssid_t * ssid; + ssid = (wlc_ssid_t *)data; + WL_TRACE(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", \ + __FUNCTION__, PNO_EVENT_UP, ssid->SSID, ssid->SSID_len)); + net_os_wake_lock_timeout_enable(dev); + cmd = IWEVCUSTOM; + memset(&wrqu, 0, sizeof(wrqu)); + strcpy(extra, PNO_EVENT_UP); + wrqu.data.length = strlen(extra); + } + break; + default: WL_TRACE(("Unknown Event %d: ignoring\n", event_type)); @@ -7290,6 +7727,8 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) if (!dev) return 0; + memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t)); + #ifdef CSCAN params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); @@ -7313,7 +7752,7 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; g_iscan->scan_flag = 0; - iscan->timer_ms = 3000; + iscan->timer_ms = 8000; init_timer(&iscan->timer); iscan->timer.data = (ulong)iscan; iscan->timer.function = wl_iw_timerfunc; diff --git a/bcm4329/src/wl/sys/wl_iw.h b/bcm4329/src/wl/sys/wl_iw.h index d49ce24..866fbd5 100644 --- a/bcm4329/src/wl/sys/wl_iw.h +++ b/bcm4329/src/wl/sys/wl_iw.h @@ -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: wl_iw.h,v 1.5.34.1.6.24 2010/07/27 20:46:02 Exp $ + * $Id: wl_iw.h,v 1.5.34.1.6.35 2010/08/20 02:42:33 Exp $ */ @@ -45,6 +45,21 @@ #define BAND_GET_CMD "GETBAND" #define BAND_SET_CMD "SETBAND" +#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" +#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" +#define SETSUSPEND_CMD "SETSUSPEND" +#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" +#define PNOSETUP_SET_CMD "PNOSETUP" +#define PNOENABLE_SET_CMD "PNOFORCE" +#define PNODEBUG_SET_CMD "PNODEBUG" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + + +typedef struct wl_iw_extra_params { + int target_channel; +} wl_iw_extra_params_t; #define WL_IW_RSSI_MINVAL -200 #define WL_IW_RSSI_NO_SIGNAL -91 @@ -178,6 +193,10 @@ extern int net_os_wake_unlock(struct net_device *dev); extern int net_os_wake_lock_timeout(struct net_device *dev); extern int net_os_wake_lock_timeout_enable(struct net_device *dev); extern int net_os_set_suspend_disable(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val); +extern int net_os_set_dtim_skip(struct net_device *dev, int val); +extern int net_os_set_packet_filter(struct net_device *dev, int val); +extern int net_os_send_hang_message(struct net_device *dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ @@ -195,6 +214,31 @@ extern int net_os_set_suspend_disable(struct net_device *dev, int val); iwe_stream_add_point(stream, ends, iwe, extra) #endif +extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); +extern int dhd_pno_clean(dhd_pub_t *dhd); +extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, uchar scan_fr); +extern int dhd_pno_get_status(dhd_pub_t *dhd); +extern int dhd_dev_pno_reset(struct net_device *dev); +extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, \ + int nssid, uchar scan_fr); +extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); +extern int dhd_dev_get_pno_status(struct net_device *dev); + +#define PNO_TLV_PREFIX 'S' +#define PNO_TLV_VERSION 1 +#define PNO_TLV_SUBVERSION 0 +#define PNO_TLV_RESERVED 0 +#define PNO_TLV_TYPE_SSID_IE 'S' +#define PNO_TLV_TYPE_TIME 'T' +#define PNO_EVENT_UP "PNO_EVENT" + +typedef struct cmd_tlv { + char prefix; + char version; + char subver; + char reserved; +} cmd_tlv_t; + #if defined(CSCAN) typedef struct cscan_tlv { |