From: lbt Date: Thu, 27 Jan 2011 03:22:17 +0000 (+0800) Subject: wireless: bcm4329 wlan driver update to 4.218.248.6 X-Git-Tag: firefly_0821_release~10789^2~4 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1ce1a68c19b628de1881018c72ba6c125d5dfea9;p=firefly-linux-kernel-4.4.55.git wireless: bcm4329 wlan driver update to 4.218.248.6 --- diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index 46317ec0ad28..d740f1378fe2 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -90,6 +90,7 @@ struct wifi_platform_data { int (*set_reset)(int val); int (*set_carddetect)(int val); void *(*mem_prealloc)(int section, unsigned long size); + int (*get_mac_addr)(unsigned char *buf); }; struct rk29_sdmmc_platform_data { diff --git a/drivers/net/wireless/bcm4329/Kconfig b/drivers/net/wireless/bcm4329/Kconfig index b50bcf077af4..aa4355a6225e 100644 --- a/drivers/net/wireless/bcm4329/Kconfig +++ b/drivers/net/wireless/bcm4329/Kconfig @@ -1,16 +1,27 @@ - -choice BCM4329_MODULE_NAME - depends on BCM4329 - prompt "BCM4329 WiFi module" +config BCM4329 + tristate "Broadcom 4329 wireless cards support" + depends on MMC + select WIRELESS_EXT + select WEXT_PRIV ---help--- - Different module need own firmware file even if they - are based on the same BCM4329 WiFi chip. + This module adds support for wireless adapters based on + Broadcom 4329 chipset. - config BCM4329_SAMSUNG_B23 - bool "Samsung SWL-B23" + This driver uses the kernel's wireless extensions subsystem. - config BCM4329_USI - bool "USI SWL-B23" + If you choose to build a module, it'll be called dhd. Say M if + unsure. -endchoice +config BCM4329_FW_PATH + depends on BCM4329 + string "Firmware path" + default "/system/etc/firmware/fw_bcm4329.bin" + ---help--- + Path to the firmware file. +config BCM4329_NVRAM_PATH + depends on BCM4329 + string "NVRAM path" + default "/system/etc/firmware/nvram_B23.txt" + ---help--- + Path to the calibration file. diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile index 26d61b83d6cc..3f3b0b0f21b9 100755 --- a/drivers/net/wireless/bcm4329/Makefile +++ b/drivers/net/wireless/bcm4329/Makefile @@ -1,32 +1,23 @@ -EXTRA_CFLAGS += -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include \ - -DLINUX -DSRCBASE=\"$(BROADCOM_SRC_DIR)\" -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD \ - -DBCMWPA2 -DBCMWAPI_WPI -DUNRELEASEDCHIP -DOEM_ANDROID -DEMBEDDED_PLATFORM \ - -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC \ - -DBCMPLATFORM_BUS -DSDIO_ISR_THREAD -DBDC -DTOE -DDHD_BCMEVENTS -DSHOW_EVENTS \ - -DDHD_SCHED -DDHD_DEBUG -DSDTEST -Wall -Wstrict-prototypes -Werror - - -bcmsdio-objs := bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o \ - bcmsdh_sdmmc_linux.o - -dhd-objs := dhd_common.o dhd_linux.o dhd_linux_sched.o dhd_sdio.o \ - dhd_custom_gpio.o dhd_cdc.o - -shared-objs := aiutils.o bcmutils.o bcmwifi.o hndpmu.o \ - linux_osl.o sbutils.o siutils.o - -wl-objs := wl_iw.o - -bcm4329-objs := $(bcmsdio-objs) $(dhd-objs) $(shared-objs) $(wl-objs) +# bcm4329 +DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \ + -DUNRELEASEDCHIP -Dlinux -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 \ + -DDHD_FIRSTREAD=64 -DDHD_GPL -DDHD_SCHED -DBDC -DTOE -DDHD_BCMEVENTS \ + -DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \ + -Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 \ + -DDHD_DEBUG_TRAP -DSOFTAP \ + -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \ + -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP \ + -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include + +#options defines dependent on platform board and applicantion requirements: +#-DOOB_INTR_ONLY -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DHW_OOB -DCSCAN + +DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ + wl_iw.o siutils.o sbutils.o aiutils.o hndpmu.o bcmwifi.o dhd_sdio.o \ + dhd_linux_sched.o dhd_cdc.o bcmsdh_sdmmc.o bcmsdh.o bcmsdh_linux.o \ + bcmsdh_sdmmc_linux.o obj-$(CONFIG_BCM4329) += bcm4329.o - - - - - - - - - - +bcm4329-objs += $(DHDOFILES) +EXTRA_CFLAGS = $(DHDCFLAGS) +EXTRA_LDFLAGS += --strip-debug diff --git a/drivers/net/wireless/bcm4329/bcmpcispi.c b/drivers/net/wireless/bcm4329/bcmpcispi.c index c0a66f1aa3e4..1a8b6717f924 100644 --- a/drivers/net/wireless/bcm4329/bcmpcispi.c +++ b/drivers/net/wireless/bcm4329/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 @@ -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/drivers/net/wireless/bcm4329/bcmsdh_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_linux.c index 79d610bf6b45..559f4819b1b6 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_linux.c +++ b/drivers/net/wireless/bcm4329/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.4.2 2010/09/15 00:30:11 Exp $ */ /** @@ -76,6 +76,10 @@ struct bcmsdh_hc { void *ch; unsigned int oob_irq; 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; @@ -187,7 +191,12 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ #if defined(OOB_INTR_ONLY) - irq_flags = IRQF_TRIGGER_FALLING; +#ifdef HW_OOB + irq_flags = \ + IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; +#else + irq_flags = IRQF_TRIGGER_FALLING; +#endif /* HW_OOB */ irq = dhd_customer_oob_irq_map(&irq_flags); if (irq < 0) { SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); @@ -226,6 +235,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; @@ -332,18 +345,18 @@ static struct pci_driver bcmsdh_pci_driver = { #endif suspend: NULL, resume: NULL, - }; +}; 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 */ - /* Upper word is bus number, */ - /* lower word is slot number */ - /* Default value of 0xFFFFffff turns this */ - /* off */ + /* slot only . Allows for having multiple */ + /* WL devices at once in a PC */ + /* Only one instance of dhd will be */ + /* usable at a time */ + /* Upper word is bus number, */ + /* lower word is slot number */ + /* Default value of 0xFFFFffff turns this */ + /* off */ module_param(sd_pci_slot, uint, 0); @@ -366,20 +379,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) || @@ -440,7 +454,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), @@ -567,21 +581,38 @@ 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; } - WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); - dhdsdio_isr((void *)dhdp->bus); return IRQ_HANDLED; @@ -595,15 +626,18 @@ int bcmsdh_register_oob_intr(void * dhdp) dev_set_drvdata(sdhcinfo->dev, dhdp); + if (!sdhcinfo->oob_irq_registered) { + SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, \ + (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags)); + /* 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; - /* 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; } @@ -615,14 +649,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/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c index 6581614c0ebf..bda919390587 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.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.c,v 1.1.2.5.6.29 2010/03/19 17:16:08 Exp $ + * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.30.4.1 2010/09/02 23:12:21 Exp $ */ #include @@ -55,7 +55,7 @@ extern void sdio_function_cleanup(void); #if !defined(OOB_INTR_ONLY) static void IRQHandler(struct sdio_func *func); static void IRQHandlerF2(struct sdio_func *func); -#endif +#endif /* !defined(OOB_INTR_ONLY) */ static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); extern int sdio_reset_comm(struct mmc_card *card); @@ -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; } @@ -1064,14 +1066,18 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u return (Status); } +/* this function performs "abort" for both of host & device */ extern int sdioh_abort(sdioh_info_t *sd, uint func) { +#if defined(MMC_SDIO_ABORT) + char t_func = (char) func; +#endif /* defined(MMC_SDIO_ABORT) */ sd_trace(("%s: Enter\n", __FUNCTION__)); #if defined(MMC_SDIO_ABORT) /* issue abort cmd52 command through F1 */ - sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, (uint8 *)&func); + sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); #endif /* defined(MMC_SDIO_ABORT) */ sd_trace(("%s: Exit\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c index 5260b482a8df..8992a4267f9f 100644 --- a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcm4329/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 @@ -34,19 +34,27 @@ #include #include -#include #include #include #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 @@ -117,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 */ }, }; @@ -242,6 +253,7 @@ int sdio_function_init(void) bzero(&sdmmc_dev, sizeof(sdmmc_dev)); error = sdio_register_driver(&bcmsdh_sdmmc_driver); + return error; } diff --git a/drivers/net/wireless/bcm4329/bcmsdstd.c b/drivers/net/wireless/bcm4329/bcmsdstd.c index 0b1b575d9629..0ca1f8ff8a24 100644 --- a/drivers/net/wireless/bcm4329/bcmsdstd.c +++ b/drivers/net/wireless/bcm4329/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 @@ -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/drivers/net/wireless/bcm4329/bcmsdstd_linux.c b/drivers/net/wireless/bcm4329/bcmsdstd_linux.c index ad6d6603fccd..a8b98e2054a0 100644 --- a/drivers/net/wireless/bcm4329/bcmsdstd_linux.c +++ b/drivers/net/wireless/bcm4329/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 @@ -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/drivers/net/wireless/bcm4329/bcmspibrcm.c b/drivers/net/wireless/bcm4329/bcmspibrcm.c new file mode 100644 index 000000000000..0f131a40f4b8 --- /dev/null +++ b/drivers/net/wireless/bcm4329/bcmspibrcm.c @@ -0,0 +1,1726 @@ +/* + * Broadcom BCMSDH to gSPI Protocol Conversion Layer + * + * Copyright (C) 2010, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: bcmspibrcm.c,v 1.11.2.10.2.9.6.11 2009/05/21 13:21:57 Exp $ + */ + +#define HSMODE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* bcmsdh to/from specific controller APIs */ +#include /* ioctl/iovars */ +#include + +#include + + +#include +#include + +#define F0_RESPONSE_DELAY 16 +#define F1_RESPONSE_DELAY 16 +#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY + +#define CMDLEN 4 + +#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE) + +/* Globals */ +uint sd_msglevel = 0; + +uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ +uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ +uint sd_f2_blocksize = 64; /* Default blocksize */ + + +uint sd_divisor = 2; +uint sd_power = 1; /* Default to SD Slot powered ON */ +uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ + +uint8 spi_outbuf[SPI_MAX_PKT_LEN]; +uint8 spi_inbuf[SPI_MAX_PKT_LEN]; + +/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits + * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. + */ +#define BUF2_PKT_LEN 128 +uint8 spi_outbuf2[BUF2_PKT_LEN]; +uint8 spi_inbuf2[BUF2_PKT_LEN]; + +/* Prototypes */ +static bool bcmspi_test_card(sdioh_info_t *sd); +static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); +static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); +static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen); +static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 *data); +static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, + int regsize, uint32 data); +static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, + uint8 *data); +static int bcmspi_driver_init(sdioh_info_t *sd); +static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data); +static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, + uint32 *data); +static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); +static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); + +/* + * Public entry points & extern's + */ +extern sdioh_info_t * +sdioh_attach(osl_t *osh, void *bar0, uint irq) +{ + sdioh_info_t *sd; + + sd_trace(("%s\n", __FUNCTION__)); + if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { + sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); + return NULL; + } + bzero((char *)sd, sizeof(sdioh_info_t)); + sd->osh = osh; + if (spi_osinit(sd) != 0) { + sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return NULL; + } + + sd->bar0 = bar0; + sd->irq = irq; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + sd->intr_handler_valid = FALSE; + + /* Set defaults */ + sd->use_client_ints = TRUE; + sd->sd_use_dma = FALSE; /* DMA Not supported */ + + /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit + * mode + */ + sd->wordlen = 2; + + if (!spi_hw_attach(sd)) { + sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (bcmspi_driver_init(sd) != SUCCESS) { + sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + if (spi_register_irq(sd, irq) != SUCCESS) { + sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + return (NULL); + } + + sd_trace(("%s: Done\n", __FUNCTION__)); + + return sd; +} + +extern SDIOH_API_RC +sdioh_detach(osl_t *osh, sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if (sd) { + sd_err(("%s: detaching from hardware\n", __FUNCTION__)); + spi_free_irq(sd->irq, sd); + spi_hw_detach(sd); + spi_osfree(sd); + MFREE(sd->osh, sd, sizeof(sdioh_info_t)); + } + return SDIOH_API_RC_SUCCESS; +} + +/* Configure callback to client when we recieve client interrupt */ +extern SDIOH_API_RC +sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler = fn; + sd->intr_handler_arg = argh; + sd->intr_handler_valid = TRUE; + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_deregister(sdioh_info_t *sd) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + sd->intr_handler_valid = FALSE; + sd->intr_handler = NULL; + sd->intr_handler_arg = NULL; + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) +{ + sd_trace(("%s: Entering\n", __FUNCTION__)); + *onoff = sd->client_intr_enabled; + return SDIOH_API_RC_SUCCESS; +} + +#if defined(DHD_DEBUG) +extern bool +sdioh_interrupt_pending(sdioh_info_t *sd) +{ + return 0; +} +#endif + +extern SDIOH_API_RC +sdioh_query_device(sdioh_info_t *sd) +{ + /* Return a BRCM ID appropriate to the dongle class */ + return (sd->num_funcs > 1) ? BCM4329_D11NDUAL_ID : BCM4318_D11G_ID; +} + +/* Provide dstatus bits of spi-transaction for dhd layers. */ +extern uint32 +sdioh_get_dstatus(sdioh_info_t *sd) +{ + return sd->card_dstatus; +} + +extern void +sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) +{ + sd->chip = chip; + sd->chiprev = chiprev; +} + +extern void +sdioh_dwordmode(sdioh_info_t *sd, bool set) +{ + uint8 reg = 0; + int status; + + if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } + + if (set) { + reg |= DWORD_PKT_LEN_EN; + sd->dwordmode = TRUE; + sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ + } else { + reg &= ~DWORD_PKT_LEN_EN; + sd->dwordmode = FALSE; + sd->client_block_size[SPI_FUNC_2] = 2048; + } + + if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != + SUCCESS) { + sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); + return; + } +} + + +uint +sdioh_query_iofnum(sdioh_info_t *sd) +{ + return sd->num_funcs; +} + +/* IOVar table */ +enum { + IOV_MSGLEVEL = 1, + IOV_BLOCKMODE, + IOV_BLOCKSIZE, + IOV_DMA, + IOV_USEINTS, + IOV_NUMINTS, + IOV_NUMLOCALINTS, + IOV_HOSTREG, + IOV_DEVREG, + IOV_DIVISOR, + IOV_SDMODE, + IOV_HISPEED, + IOV_HCIREGS, + IOV_POWER, + IOV_CLOCK, + IOV_SPIERRSTATS, + IOV_RESP_DELAY_ALL +}; + +const bcm_iovar_t sdioh_iovars[] = { + {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, + {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ + {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, + {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, + {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, + {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, + {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, + {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, + {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, + {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, + {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, + {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, + {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, + {NULL, 0, 0, 0, 0 } +}; + +int +sdioh_iovar_op(sdioh_info_t *si, const char *name, + void *params, int plen, void *arg, int len, bool set) +{ + const bcm_iovar_t *vi = NULL; + int bcmerror = 0; + int val_size; + int32 int_val = 0; + bool bool_val; + uint32 actionid; +/* + sdioh_regs_t *regs; +*/ + + ASSERT(name); + ASSERT(len >= 0); + + /* Get must have return space; Set does not take qualifiers */ + ASSERT(set || (arg && len)); + ASSERT(!set || (!params && !plen)); + + sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); + + if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { + bcmerror = BCME_UNSUPPORTED; + goto exit; + } + + if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) + goto exit; + + /* Set up params so get and set can share the convenience variables */ + if (params == NULL) { + params = arg; + plen = len; + } + + if (vi->type == IOVT_VOID) + val_size = 0; + else if (vi->type == IOVT_BUFFER) + val_size = len; + else + val_size = sizeof(int); + + if (plen >= (int)sizeof(int_val)) + bcopy(params, &int_val, sizeof(int_val)); + + bool_val = (int_val != 0) ? TRUE : FALSE; + + actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + switch (actionid) { + case IOV_GVAL(IOV_MSGLEVEL): + int_val = (int32)sd_msglevel; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_MSGLEVEL): + sd_msglevel = int_val; + break; + + case IOV_GVAL(IOV_BLOCKSIZE): + if ((uint32)int_val > si->num_funcs) { + bcmerror = BCME_BADARG; + break; + } + int_val = (int32)si->client_block_size[int_val]; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_DMA): + int_val = (int32)si->sd_use_dma; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DMA): + si->sd_use_dma = (bool)int_val; + break; + + case IOV_GVAL(IOV_USEINTS): + int_val = (int32)si->use_client_ints; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_USEINTS): + break; + + case IOV_GVAL(IOV_DIVISOR): + int_val = (uint32)sd_divisor; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DIVISOR): + sd_divisor = int_val; + if (!spi_start_clock(si, (uint16)sd_divisor)) { + sd_err(("%s: set clock failed\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + } + break; + + case IOV_GVAL(IOV_POWER): + int_val = (uint32)sd_power; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_POWER): + sd_power = int_val; + break; + + case IOV_GVAL(IOV_CLOCK): + int_val = (uint32)sd_clock; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_CLOCK): + sd_clock = int_val; + break; + + case IOV_GVAL(IOV_SDMODE): + int_val = (uint32)sd_sdmode; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SDMODE): + sd_sdmode = int_val; + break; + + case IOV_GVAL(IOV_HISPEED): + int_val = (uint32)sd_hiok; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_HISPEED): + sd_hiok = int_val; + + if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { + sd_err(("%s: Failed changing highspeed mode to %d.\n", + __FUNCTION__, sd_hiok)); + bcmerror = BCME_ERROR; + return ERROR; + } + break; + + case IOV_GVAL(IOV_NUMINTS): + int_val = (int32)si->intrcount; + bcopy(&int_val, arg, val_size); + break; + + case IOV_GVAL(IOV_NUMLOCALINTS): + int_val = (int32)si->local_intrcount; + bcopy(&int_val, arg, val_size); + break; + case IOV_GVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data; + + if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + + int_val = (int)data; + bcopy(&int_val, arg, sizeof(int_val)); + break; + } + + case IOV_SVAL(IOV_DEVREG): + { + sdreg_t *sd_ptr = (sdreg_t *)params; + uint8 data = (uint8)sd_ptr->value; + + if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + } + + + case IOV_GVAL(IOV_SPIERRSTATS): + { + bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); + break; + } + + case IOV_SVAL(IOV_SPIERRSTATS): + { + bzero(&si->spierrstats, sizeof(struct spierrstats_t)); + break; + } + + case IOV_GVAL(IOV_RESP_DELAY_ALL): + int_val = (int32)si->resp_delay_all; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_RESP_DELAY_ALL): + si->resp_delay_all = (bool)int_val; + int_val = STATUS_ENABLE|INTR_WITH_STATUS; + if (si->resp_delay_all) + int_val |= RESP_DELAY_ALL; + else { + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, + F1_RESPONSE_DELAY) != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + } + + if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) + != SUCCESS) { + sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); + bcmerror = BCME_SDIO_ERROR; + break; + } + break; + + default: + bcmerror = BCME_UNSUPPORTED; + break; + } +exit: + + return bcmerror; +} + +extern SDIOH_API_RC +sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + SDIOH_API_RC status; + /* No lock needed since sdioh_request_byte does locking */ + status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) +{ + /* No lock needed since sdioh_request_byte does locking */ + SDIOH_API_RC status; + + if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { + uint8 dummy_data; + status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); + if (status) { + sd_err(("sdioh_cfg_read() failed.\n")); + return status; + } + } + + status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); + return status; +} + +extern SDIOH_API_RC +sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) +{ + uint32 count; + int offset; + uint32 cis_byte; + uint16 *cis = (uint16 *)cisd; + uint bar0 = SI_ENUM_BASE; + int status; + uint8 data; + + sd_trace(("%s: Func %d\n", __FUNCTION__, func)); + + spi_lock(sd); + + /* Set sb window address to 0x18000000 */ + data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); + if (status == SUCCESS) { + data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + if (status == SUCCESS) { + data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; + status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); + } else { + sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + offset = CC_OTP; /* OTP offset in chipcommon. */ + for (count = 0; count < length/2; count++) { + if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { + sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); + spi_unlock(sd); + return (BCME_ERROR); + } + + *cis = (uint16)cis_byte; + cis++; + offset += 2; + } + + spi_unlock(sd); + + return (BCME_OK); +} + +extern SDIOH_API_RC +sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + spi_lock(sd); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, rw, func, + regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, + cmd_arg, &data, 1)) != SUCCESS) { + spi_unlock(sd); + return status; + } + + if (rw == SDIOH_READ) + *byte = (uint8)data; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, + uint32 *word, uint nbytes) +{ + int status; + + spi_lock(sd); + + if (rw == SDIOH_READ) + status = bcmspi_card_regread(sd, func, addr, nbytes, word); + else + status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); + + spi_unlock(sd); + return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); +} + +extern SDIOH_API_RC +sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, + uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) +{ + int len; + int buflen = (int)buflen_u; + bool fifo = (fix_inc == SDIOH_DATA_FIX); + + spi_lock(sd); + + ASSERT(reg_width == 4); + ASSERT(buflen_u < (1 << 30)); + ASSERT(sd->client_block_size[func]); + + sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", + __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', + buflen_u, sd->r_cnt, sd->t_cnt, pkt)); + + /* Break buffer down into blocksize chunks. */ + while (buflen > 0) { + len = MIN(sd->client_block_size[func], buflen); + if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { + sd_err(("%s: bcmspi_card_buf %s failed\n", + __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); + spi_unlock(sd); + return SDIOH_API_RC_FAIL; + } + buffer += len; + buflen -= len; + if (!fifo) + addr += len; + } + spi_unlock(sd); + return SDIOH_API_RC_SUCCESS; +} + +/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. + * Its main aim is to have simpler spi writes rather than recursive writes. + * e.g. When there is a need to program response delay on the fly after detecting the SPI-func + * this call will allow to program the response delay. + */ +static int +bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) +{ + uint32 cmd_arg; + uint32 datalen = 1; + uint32 hostlen; + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf2 = bcmswap32(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)spi_outbuf2 = bcmswap16(cmd_arg & 0xffff); + *(uint16 *)&spi_outbuf2[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16); + if (datalen & 0x1) + datalen++; + } else { + sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (datalen != 0) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf2[CMDLEN] = bcmswap32(byte); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)&spi_outbuf2[CMDLEN] = bcmswap16(byte & 0xffff); + *(uint16 *)&spi_outbuf2[CMDLEN + 2] = + bcmswap16((byte & 0xffff0000) >> 16); + } + } + + /* +4 for cmd, +4 for dstatus */ + hostlen = datalen + 8; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) | + (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16)); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +/* Program the response delay corresponding to the spi function */ +static int +bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) +{ + if (sd->resp_delay_all == FALSE) + return (BCME_OK); + + if (sd->prev_fun == func) + return (BCME_OK); + + if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) + return (BCME_OK); + + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); + + /* Remember function for which to avoid reprogramming resp-delay in next iteration */ + sd->prev_fun = func; + + return (BCME_OK); + +} + +#define GSPI_RESYNC_PATTERN 0x0 + +/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. + * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is + * synchronised and all queued resuests are cancelled. + */ +static int +bcmspi_resync_f1(sdioh_info_t *sd) +{ + uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; + + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + ASSERT(sd->wordlen == 4 || sd->wordlen == 2); + datalen = ROUNDUP(datalen, sd->wordlen); + + /* Start by copying command in the spi-outbuffer */ + *(uint32 *)spi_outbuf2 = cmd_arg; + + /* for Write, put the data into the output buffer */ + *(uint32 *)&spi_outbuf2[CMDLEN] = data; + + /* +4 for cmd, +4 for dstatus */ + spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); + + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN ]) | + (bcmswap16(*(uint16 *)&spi_inbuf2[datalen + CMDLEN + 2]) << 16)); + } else { + sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", + __FUNCTION__, 8 * sd->wordlen)); + return ERROR; + } + + if (sd->card_dstatus) + sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); + + return (BCME_OK); +} + +uint32 dstatus_count = 0; + +static int +bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) +{ + uint32 dstatus = sd->card_dstatus; + struct spierrstats_t *spierrstats = &sd->spierrstats; + int err = SUCCESS; + + sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); + + /* Store dstatus of last few gSPI transactions */ + spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; + spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; + dstatus_count++; + + if (sd->card_init_done == FALSE) + return err; + + if (dstatus & STATUS_DATA_NOT_AVAILABLE) { + spierrstats->dna++; + sd_trace(("Read data not available on F1 addr = 0x%x\n", + GFIELD(cmd_arg, SPI_REG_ADDR))); + /* Clear dna bit */ + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); + } + + if (dstatus & STATUS_UNDERFLOW) { + spierrstats->rdunderflow++; + sd_err(("FIFO underflow happened due to current F2 read command.\n")); + } + + if (dstatus & STATUS_OVERFLOW) { + spierrstats->wroverflow++; + sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); + if ((sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 0)) { + bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); + bcmspi_resync_f1(sd); + sd_err(("Recovering from F1 FIFO overflow.\n")); + } else { + err = ERROR_OF; + } + } + + if (dstatus & STATUS_F2_INTR) { + spierrstats->f2interrupt++; + sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_F3_INTR) { + spierrstats->f3interrupt++; + sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); + } + + if (dstatus & STATUS_HOST_CMD_DATA_ERR) { + spierrstats->hostcmddataerr++; + sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); + } + + if (dstatus & STATUS_F2_PKT_AVAILABLE) { + spierrstats->f2pktavailable++; + sd_trace(("Packet is available/ready in F2 TX FIFO\n")); + sd_trace(("Packet length = %d\n", sd->dwordmode ? + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : + ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); + } + + if (dstatus & STATUS_F3_PKT_AVAILABLE) { + spierrstats->f3pktavailable++; + sd_err(("Packet is available/ready in F3 TX FIFO\n")); + sd_err(("Packet length = %d\n", + (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); + } + + return err; +} + +extern int +sdioh_abort(sdioh_info_t *sd, uint func) +{ + return 0; +} + +int +sdioh_start(sdioh_info_t *sd, int stage) +{ + return SUCCESS; +} + +int +sdioh_stop(sdioh_info_t *sd) +{ + return SUCCESS; +} + + + +/* + * Private/Static work routines + */ +static int +bcmspi_host_init(sdioh_info_t *sd) +{ + + /* Default power on mode */ + sd->sd_mode = SDIOH_MODE_SPI; + sd->polled_mode = TRUE; + sd->host_init_done = TRUE; + sd->card_init_done = FALSE; + sd->adapter_slot = 1; + + return (SUCCESS); +} + +static int +get_client_blocksize(sdioh_info_t *sd) +{ + uint32 regdata[2]; + int status; + + /* Find F1/F2/F3 max packet size */ + if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, + 8, regdata)) != SUCCESS) { + return status; + } + + sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", + regdata[0], regdata[1])); + + sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; + sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); + ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); + + sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; + sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); + ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); + + sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; + sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); + ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); + + return 0; +} + +static int +bcmspi_client_init(sdioh_info_t *sd) +{ + uint32 status_en_reg = 0; + sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); + +#ifdef HSMODE + if (!spi_start_clock(sd, (uint16)sd_divisor)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#else + /* Start at ~400KHz clock rate for initialization */ + if (!spi_start_clock(sd, 128)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + if (!bcmspi_host_device_init_adapt(sd)) { + sd_err(("bcmspi_host_device_init_adapt failed\n")); + return ERROR; + } + + if (!bcmspi_test_card(sd)) { + sd_err(("bcmspi_test_card failed\n")); + return ERROR; + } + + sd->num_funcs = SPI_MAX_IOFUNCS; + + get_client_blocksize(sd); + + /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ + bcmspi_resync_f1(sd); + + sd->dwordmode = FALSE; + + bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); + + sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); + status_en_reg |= INTR_WITH_STATUS; + + + if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, + status_en_reg & 0xff) != SUCCESS) { + sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); + return ERROR; + } + + +#ifndef HSMODE + /* After configuring for High-Speed mode, set the desired clock rate. */ + if (!spi_start_clock(sd, 4)) { + sd_err(("spi_start_clock failed\n")); + return ERROR; + } +#endif /* HSMODE */ + + sd->card_init_done = TRUE; + + + return SUCCESS; +} + +static int +bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, + 4, ®data)) != SUCCESS) + return status; + + sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); + + + if (hsmode == TRUE) { + sd_trace(("Attempting to enable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + sd_trace(("Device is already in High-Speed mode.\n")); + return status; + } else { + regdata |= HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) { + return status; + } + } + } else { + sd_trace(("Attempting to disable High-Speed mode.\n")); + + if (regdata & HIGH_SPEED_MODE) { + regdata &= ~HIGH_SPEED_MODE; + sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); + if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, + 4, regdata)) != SUCCESS) + return status; + } + else { + sd_trace(("Device is already in Low-Speed mode.\n")); + return status; + } + } + + spi_controller_highspeed_mode(sd, hsmode); + + return TRUE; +} + +#define bcmspi_find_curr_mode(sd) { \ + sd->wordlen = 2; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd->wordlen = 4; \ + status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ + regdata &= 0xff; \ + if ((regdata == 0xad) || (regdata == 0x5b) || \ + (regdata == 0x5d) || (regdata == 0x5a)) \ + break; \ + sd_trace(("Silicon testability issue: regdata = 0x%x." \ + " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ + OSL_DELAY(100000); \ +} + +#define INIT_ADAPT_LOOP 100 + +/* Adapt clock-phase-speed-bitwidth between host and device */ +static bool +bcmspi_host_device_init_adapt(sdioh_info_t *sd) +{ + uint32 wrregdata, regdata = 0; + int status; + int i; + + /* Due to a silicon testability issue, the first command from the Host + * to the device will get corrupted (first bit will be lost). So the + * Host should poll the device with a safe read request. ie: The Host + * should try to read F0 addr 0x14 using the Fixed address mode + * (This will prevent a unintended write command to be detected by device) + */ + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + /* If device was not power-cycled it will stay in 32bit mode with + * response-delay-all bit set. Alternate the iteration so that + * read either with or without response-delay for F0 to succeed. + */ + bcmspi_find_curr_mode(sd); + sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = TRUE; + + bcmspi_find_curr_mode(sd); + sd->dwordmode = FALSE; + } + + /* Bail out, device not detected */ + if (i == INIT_ADAPT_LOOP) + return FALSE; + + /* Softreset the spid logic */ + if ((sd->dwordmode) || (sd->wordlen == 4)) { + bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); + bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); + sd_trace(("reset reg read = 0x%x\n", regdata)); + sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, + sd->wordlen, sd->resp_delay_all)); + /* Restore default state after softreset */ + sd->wordlen = 2; + sd->dwordmode = FALSE; + } + + if (sd->wordlen == 4) { + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != + SUCCESS) + return FALSE; + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", + regdata)); + sd_trace(("Spid power was left on.\n")); + } else { + sd_err(("Spid power was left on but signature read failed." + " Value read = 0x%x\n", regdata)); + return FALSE; + } + } else { + sd->wordlen = 2; + +#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ + + wrregdata = (CTRL_REG_DEFAULT); + sd->resp_delay_all = TRUE; + if (sd->resp_delay_all == TRUE) { + /* Enable response delay for all */ + wrregdata |= (RESP_DELAY_ALL << 16); + /* Program response delay value */ + wrregdata &= 0xffff00ff; + wrregdata |= (F1_RESPONSE_DELAY << 8); + sd->prev_fun = SPI_FUNC_1; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + } + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); + +#ifndef HSMODE + wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); + wrregdata &= ~HIGH_SPEED_MODE; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); +#endif /* HSMODE */ + + for (i = 0; i < INIT_ADAPT_LOOP; i++) { + if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { + sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, + ®data)) != SUCCESS) + return FALSE; + } + OSL_DELAY(1000); + } + + + /* Change to host controller intr-polarity of active-low */ + wrregdata &= ~INTR_POLARITY; + sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", + wrregdata)); + /* Change to 32bit mode */ + wrregdata |= WORD_LENGTH_32; + bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); + + /* Change command/data packaging in 32bit LE mode */ + sd->wordlen = 4; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == TEST_RO_DATA_32BIT_LE) { + sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); + sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); + } else { + sd_err(("Stale spid reg values read as it was kept powered. Value read =" + "0x%x\n", regdata)); + return FALSE; + } + } + + + return TRUE; +} + +static bool +bcmspi_test_card(sdioh_info_t *sd) +{ + uint32 regdata; + int status; + + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) + return FALSE; + + if (regdata == (TEST_RO_DATA_32BIT_LE)) + sd_trace(("32bit LE regdata = 0x%x\n", regdata)); + else { + sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); + return FALSE; + } + + +#define RW_PATTERN1 0xA0A1A2A3 +#define RW_PATTERN2 0x4B5B6B7B + + regdata = RW_PATTERN1; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN1) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN1, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + regdata = RW_PATTERN2; + if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) + return FALSE; + regdata = 0; + if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) + return FALSE; + if (regdata != RW_PATTERN2) { + sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", + RW_PATTERN2, regdata)); + return FALSE; + } else + sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); + + return TRUE; +} + +static int +bcmspi_driver_init(sdioh_info_t *sd) +{ + sd_trace(("%s\n", __FUNCTION__)); + if ((bcmspi_host_init(sd)) != SUCCESS) { + return ERROR; + } + + if (bcmspi_client_init(sd) != SUCCESS) { + return ERROR; + } + + return SUCCESS; +} + +/* Read device reg */ +static int +bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func, + regaddr, *data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) + != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +static int +bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) +{ + + int status; + uint32 cmd_arg; + uint32 dstatus; + + ASSERT(regsize); + + if (func == 2) + sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) + != SUCCESS) + return status; + + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 0, func, + regaddr, *data)); + + bcmspi_cmd_getdstatus(sd, &dstatus); + sd_trace(("dstatus =0x%x\n", dstatus)); + return SUCCESS; +} + +/* write a device register */ +static int +bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) +{ + int status; + uint32 cmd_arg, dstatus; + + ASSERT(regsize); + + cmd_arg = 0; + + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, 1, func, + regaddr, data)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) + != SUCCESS) + return status; + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +/* write a device register - 1 byte */ +static int +bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) +{ + int status; + uint32 cmd_arg; + uint32 dstatus; + uint32 data = (uint32)(*byte); + + cmd_arg = 0; + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_trace(("%s: func=%d, regaddr=0x%08x, data=0x%x\n", __FUNCTION__, func, + regaddr, data)); + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, + cmd_arg, &data, 1)) != SUCCESS) { + return status; + } + + bcmspi_cmd_getdstatus(sd, &dstatus); + if (dstatus) + sd_trace(("dstatus =0x%x\n", dstatus)); + + return SUCCESS; +} + +void +bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) +{ + *dstatus_buffer = sd->card_dstatus; +} + +/* 'data' is of type uint32 whereas other buffers are of type uint8 */ +static int +bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, + uint32 *data, uint32 datalen) +{ + uint32 i, j; + uint8 resp_delay = 0; + int err = SUCCESS; + uint32 hostlen; + uint32 spilen = 0; + uint32 dstatus_idx = 0; + uint16 templen, buslen, len, *ptr = NULL; + + sd_trace(("spi cmd = 0x%x\n", cmd_arg)); + + if (DWORDMODE_ON) { + spilen = GFIELD(cmd_arg, SPI_LEN); + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) || + (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1)) + dstatus_idx = spilen * 3; + + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + spilen = spilen << 2; + dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0; + /* convert len to mod16 size */ + spilen = ROUNDUP(spilen, 16); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } + } + + /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen + * according to the wordlen mode(16/32bit) the device is in. + */ + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)spi_outbuf = bcmswap32(cmd_arg); + if (datalen & 0x3) + datalen += (4 - (datalen & 0x3)); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)spi_outbuf = bcmswap16(cmd_arg & 0xffff); + *(uint16 *)&spi_outbuf[2] = bcmswap16((cmd_arg & 0xffff0000) >> 16); + if (datalen & 0x1) + datalen++; + if (datalen < 4) + datalen = ROUNDUP(datalen, 4); + } else { + sd_err(("Host is %d bit spid, could not create SPI command.\n", + 8 * sd->wordlen)); + return ERROR; + } + + /* for Write, put the data into the output buffer */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { + /* We send len field of hw-header always a mod16 size, both from host and dongle */ + if (DWORDMODE_ON) { + if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + /* ASSERT(*ptr == ~*(ptr + 1)); */ + templen = ROUNDUP(templen, 16); + *ptr = templen; + sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1)))); + } + } + + if (datalen != 0) { + for (i = 0; i < datalen/4; i++) { + if (sd->wordlen == 4) { /* 32bit spid */ + *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = + bcmswap32(data[i]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + *(uint16 *)&spi_outbuf[i * 4 + CMDLEN] = + bcmswap16(data[i] & 0xffff); + *(uint16 *)&spi_outbuf[i * 4 + CMDLEN + 2] = + bcmswap16((data[i] & 0xffff0000) >> 16); + } + } + } + } + + /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { + int func = GFIELD(cmd_arg, SPI_FUNCTION); + switch (func) { + case 0: + resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; + break; + case 1: + resp_delay = F1_RESPONSE_DELAY; + break; + case 2: + resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; + break; + default: + ASSERT(0); + break; + } + /* Program response delay */ + bcmspi_prog_resp_delay(sd, func, resp_delay); + } + + /* +4 for cmd and +4 for dstatus */ + hostlen = datalen + 8 + resp_delay; + hostlen += dstatus_idx; + hostlen += (4 - (hostlen & 0x3)); + spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); + + /* for Read, get the data into the input buffer */ + if (datalen != 0) { + if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ + for (j = 0; j < datalen/4; j++) { + if (sd->wordlen == 4) { /* 32bit spid */ + data[j] = bcmswap32(*(uint32 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + data[j] = (bcmswap16(*(uint16 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay])) | + ((bcmswap16(*(uint16 *)&spi_inbuf[j * 4 + + CMDLEN + resp_delay + 2])) << 16); + } + } + + if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + ptr = (uint16 *)&data[0]; + templen = *ptr; + buslen = len = ~(*(ptr + 1)); + buslen = ROUNDUP(buslen, 16); + /* populate actual len in hw-header */ + if (templen == buslen) + *ptr = len; + } + } + } + + /* Restore back the len field of the hw header */ + if (DWORDMODE_ON) { + if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) && + (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) { + ptr = (uint16 *)&data[0]; + *ptr = (uint16)(~*(ptr+1)); + } + } + + dstatus_idx += (datalen + CMDLEN + resp_delay); + /* Last 4bytes are dstatus. Device is configured to return status bits. */ + if (sd->wordlen == 4) { /* 32bit spid */ + sd->card_dstatus = bcmswap32(*(uint32 *)&spi_inbuf[dstatus_idx]); + } else if (sd->wordlen == 2) { /* 16bit spid */ + sd->card_dstatus = (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx]) | + (bcmswap16(*(uint16 *)&spi_inbuf[dstatus_idx + 2]) << 16)); + } else { + sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", + 8 * sd->wordlen)); + return ERROR; + } + if (sd->card_dstatus == 0xffffffff) { + sd_err(("looks like not a GSPI device or device is not powered.\n")); + } + + err = bcmspi_update_stats(sd, cmd_arg); + + return err; + +} + +static int +bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, + uint32 addr, int nbytes, uint32 *data) +{ + int status; + uint32 cmd_arg; + bool write = rw == SDIOH_READ ? 0 : 1; + uint retries = 0; + + bool enable; + uint32 spilen; + + cmd_arg = 0; + + ASSERT(nbytes); + ASSERT(nbytes <= sd->client_block_size[func]); + + if (write) sd->t_cnt++; else sd->r_cnt++; + + if (func == 2) { + /* Frame len check limited by gSPI. */ + if ((nbytes > 2000) && write) { + sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); + } + /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ + /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ + if (write) { + uint32 dstatus; + /* check F2 ready with cached one */ + bcmspi_cmd_getdstatus(sd, &dstatus); + if ((dstatus & STATUS_F2_RX_READY) == 0) { + retries = WAIT_F2RXFIFORDY; + enable = 0; + while (retries-- && !enable) { + OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); + bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, + &dstatus); + if (dstatus & STATUS_F2_RX_READY) + enable = TRUE; + } + if (!enable) { + struct spierrstats_t *spierrstats = &sd->spierrstats; + spierrstats->f2rxnotready++; + sd_err(("F2 FIFO is not ready to receive data.\n")); + return ERROR; + } + sd_trace(("No of retries on F2 ready %d\n", + (WAIT_F2RXFIFORDY - retries))); + } + } + } + + /* F2 transfers happen on 0 addr */ + addr = (func == 2) ? 0 : addr; + + /* In pio mode buffer is read using fixed address fifo in func 1 */ + if ((func == 1) && (fifo)) + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); + else + cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); + + cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); + cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); + cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); + spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); + if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { + /* convert len to mod4 size */ + spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); + cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); + } else + cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); + + if ((func == 2) && (fifo == 1)) { + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + } + + sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); + sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", + __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", + addr, nbytes, sd->r_cnt, sd->t_cnt)); + + + if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, + data, nbytes)) != SUCCESS) { + sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, + (write ? "write" : "read"))); + return status; + } + + /* gSPI expects that hw-header-len is equal to spi-command-len */ + if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { + ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); + ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); + } + + if ((nbytes > 2000) && !write) { + sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); + } + + return SUCCESS; +} + +/* Reset and re-initialize the device */ +int +sdioh_sdio_reset(sdioh_info_t *si) +{ + si->card_init_done = FALSE; + return bcmspi_client_init(si); +} diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h index 1c5f8dd796f4..5d8dc32fd304 100644 --- a/drivers/net/wireless/bcm4329/dhd.h +++ b/drivers/net/wireless/bcm4329/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 $ */ /**************** @@ -35,9 +35,6 @@ #define _dhd_h_ #if defined(LINUX) -#if defined(CHROMIUMOS_COMPAT_WIRELESS) -#include -#endif #include #include #include @@ -49,9 +46,7 @@ #include #include #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -#include -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ + /* The kernel threading is sdio-specific */ #else /* LINUX */ #define ENOMEM 1 @@ -64,6 +59,11 @@ #include +#ifdef DHD_DEBUG +#ifndef DHD_DEBUG_TRAP +#define DHD_DEBUG_TRAP +#endif +#endif /* Forward decls */ struct dhd_bus; @@ -150,6 +150,14 @@ typedef struct dhd_pub { /* Last error from dongle */ int dongle_error; + /* 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]; int pktfilter_count; @@ -157,26 +165,19 @@ typedef struct dhd_pub { uint8 country_code[WLC_CNTRY_BUF_SZ]; char eventmask[WL_EVENTING_MASK_LEN]; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - struct wake_lock wakelock[WAKE_LOCK_MAX]; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ - struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -#endif } 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_timeout(a, FALSE, HZ/100); \ + 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,12 +186,12 @@ typedef struct dhd_pub { #define SPINWAIT_SLEEP(a, exp, us) do { \ uint countdown = (us) + 9999; \ while ((exp) && (countdown >= 10000)) { \ - wait_event_timeout(a, FALSE, HZ/100); \ + wait_event_interruptible_timeout(a, FALSE, HZ/100); \ countdown -= 10000; \ } \ } while (0) - #else +#else #define DHD_PM_RESUME_WAIT_INIT(a) #define DHD_PM_RESUME_WAIT(a) @@ -207,111 +208,18 @@ 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) */ -inline static void MUTEX_LOCK_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_init(&dhdp->wl_start_stop_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_lock(&dhdp->wl_start_stop_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&dhdp->wl_start_stop_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_init(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_lock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -extern struct mutex g_wl_ss_scan_lock; /* lock/unlock for Scan/Cache settings */ -#endif - -inline static void MUTEX_LOCK_WL_SCAN_SET_INIT(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_init(&g_wl_ss_scan_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_WL_SCAN_SET(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_lock(&g_wl_ss_scan_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_WL_SCAN_SET(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&g_wl_ss_scan_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void WAKE_LOCK_INIT(dhd_pub_t * dhdp, int index, char * y) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - wake_lock_init(&dhdp->wakelock[index], WAKE_LOCK_SUSPEND, y); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -} - -inline static void WAKE_LOCK(dhd_pub_t * dhdp, int index) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - wake_lock(&dhdp->wakelock[index]); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -} - -inline static void WAKE_UNLOCK(dhd_pub_t * dhdp, int index) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - wake_unlock(&dhdp->wakelock[index]); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -} - -inline static void WAKE_LOCK_TIMEOUT(dhd_pub_t * dhdp, int index, long time) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - wake_lock_timeout(&dhdp->wakelock[index], time); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -} - -inline static void WAKE_LOCK_DESTROY(dhd_pub_t * dhdp, int index) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - wake_lock_destroy(&dhdp->wakelock[index]); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -} +/* Wakelock Functions */ +extern int dhd_os_wake_lock(dhd_pub_t *pub); +extern int dhd_os_wake_unlock(dhd_pub_t *pub); +extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); +extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub); +extern void dhd_os_start_lock(dhd_pub_t *pub); +extern void dhd_os_start_unlock(dhd_pub_t *pub); typedef struct dhd_if_event { uint8 ifidx; @@ -378,7 +286,7 @@ extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_customer_gpio_wlan_ctrl(int onoff); -extern int dhd_custom_get_mac_address(unsigned char *buf); +extern int dhd_custom_get_mac_address(unsigned char *buf); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); @@ -511,9 +419,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/drivers/net/wireless/bcm4329/dhd_cdc.c b/drivers/net/wireless/bcm4329/dhd_cdc.c index e98af39c48a4..61f6a6f393a9 100644 --- a/drivers/net/wireless/bcm4329/dhd_cdc.c +++ b/drivers/net/wireless/bcm4329/dhd_cdc.c @@ -40,13 +40,9 @@ #include #include #include -#ifdef CUSTOMER_HW2 -int wifi_get_mac_addr(unsigned char *buf); -#endif extern int dhd_preinit_ioctls(dhd_pub_t *dhd); - /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN #define DHD_SDALIGN 32 @@ -78,9 +74,12 @@ dhdcdc_msg(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); + int ret; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + dhd_os_wake_lock(dhd); + /* NOTE : cdc->msg.len holds the desired length of the buffer to be * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area * is actually sent to the dongle @@ -89,7 +88,9 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ - return dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + ret = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + dhd_os_wake_unlock(dhd); + return ret; } static int @@ -322,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__)); @@ -346,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); @@ -361,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/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c index 01d05709528c..dab1ca42b338 100644 --- a/drivers/net/wireless/bcm4329/dhd_common.c +++ b/drivers/net/wireless/bcm4329/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.4.3 2010/09/10 21:30:16 Exp $ */ #include #include @@ -37,17 +37,23 @@ #include #include - #include +#ifdef SET_RANDOM_MAC_SOFTAP +#include +#include +#endif + +#ifdef GET_CUSTOM_MAC_ENABLE +int wifi_get_mac_addr(unsigned char *buf); +#endif /* GET_CUSTOM_MAC_ENABLE */ + int dhd_msg_level; -#if defined(CSCAN) #include -#endif -#define CONFIG_BCM4329_FW_PATH "/etc/firmware/fw_bcm4329.bin" -#define CONFIG_BCM4329_NVRAM_PATH "/etc/firmware/nvram_bcm4329_B23_26M.txt" +#define CONFIG_BCM4329_FW_PATH "/system/etc/firmware/fw_bcm4329.bin" +#define CONFIG_BCM4329_NVRAM_PATH "/system/etc/firmware/nvram_B23.txt" char fw_path[MOD_PARAM_PATHLEN]; char nv_path[MOD_PARAM_PATHLEN]; @@ -134,7 +140,7 @@ dhd_common_init(void) * behaviour since the value of the globals may be different on the * first time that the driver is initialized vs subsequent initializations. */ - dhd_msg_level = DHD_ERROR_VAL; + dhd_msg_level = DHD_ERROR_VAL |DHD_TRACE_VAL|DHD_INFO_VAL; #ifdef CONFIG_BCM4329_FW_PATH strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); #else @@ -231,7 +237,6 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch dhd_msg_level = int_val; break; - case IOV_GVAL(IOV_BCMERRORSTR): strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ((char *)arg)[BCME_STRLEN - 1] = 0x00; @@ -510,9 +515,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 @@ -621,16 +623,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; @@ -651,18 +643,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; @@ -968,6 +948,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) @@ -1197,7 +1178,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) { @@ -1231,6 +1214,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) @@ -1243,18 +1227,20 @@ 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 = 0; + int ret; struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ dhd_os_proto_block(dhd); #ifdef GET_CUSTOM_MAC_ENABLE - /* Read MAC address from external customer place - ** NOTE that default mac address has to be present in otp or nvram file to bring up - ** firmware but unique per board mac address maybe provided by customer code + /* + ** Read MAC address from external customer place + ** NOTE that default mac address has to be present in otp or nvram file + ** to bring up firmware but unique per board mac address maybe provided + ** by customer code */ ret = dhd_custom_get_mac_address(ea_addr.octet); if (!ret) { @@ -1262,14 +1248,36 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); if (ret < 0) { DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - } - else + } else memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); } -#endif /* GET_CUSTOM_MAC_ENABLE */ - - memset(dhd->country_code, 0, sizeof(dhd->country_code)); - strncpy(dhd->country_code,"JP", 2); //set max numbers of radio channels +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#ifdef SET_RANDOM_MAC_SOFTAP + if (strstr(fw_path, "apsta") != NULL) { + uint rand_mac; + int ret; + + srandom32((uint)jiffies); + rand_mac = random32(); + iovbuf[0] = 0x02; /* locally administered bit */ + iovbuf[1] = 0x1A; + iovbuf[2] = 0x11; + iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; + iovbuf[4] = (unsigned char)(rand_mac >> 8); + iovbuf[5] = (unsigned char)(rand_mac >> 16); + + printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]); + + bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); + ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + } else + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); + } +#endif /* SET_RANDOM_MAC_SOFTAP */ /* Set Country code */ if (dhd->country_code[0] != 0) { @@ -1307,6 +1315,52 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (dhd_roam == 0) + { + /* set internal roaming roaming parameters */ + int roam_scan_period = 30; /* in sec */ + int roam_fullscan_period = 120; /* in sec */ + int roam_trigger = -85; + int roam_delta = 15; + int band; + int band_temp_set = WLC_BAND_2G; + + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, \ + (char *)&roam_scan_period, sizeof(roam_scan_period)) < 0) + DHD_ERROR(("%s: roam scan setup failed\n", __FUNCTION__)); + + bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, \ + 4, iovbuf, sizeof(iovbuf)); + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, \ + iovbuf, sizeof(iovbuf)) < 0) + DHD_ERROR(("%s: roam fullscan setup failed\n", __FUNCTION__)); + + if (dhdcdc_query_ioctl(dhd, 0, WLC_GET_BAND, \ + (char *)&band, sizeof(band)) < 0) + DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__)); + else { + if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_ALL)) + { + /* temp set band to insert new roams values */ + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \ + (char *)&band_temp_set, sizeof(band_temp_set)) < 0) + DHD_ERROR(("%s: local band seting failed\n", __FUNCTION__)); + } + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_DELTA, \ + (char *)&roam_delta, sizeof(roam_delta)) < 0) + DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__)); + + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_TRIGGER, \ + (char *)&roam_trigger, sizeof(roam_trigger)) < 0) + DHD_ERROR(("%s: roam trigger setting failed\n", __FUNCTION__)); + + /* Restore original band settinngs */ + if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \ + (char *)&band, sizeof(band)) < 0) + DHD_ERROR(("%s: Original band restore failed\n", __FUNCTION__)); + } + } + /* Force STA UP */ if (dhd_radio_up) dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up)); @@ -1366,9 +1420,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; @@ -1529,10 +1583,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; @@ -1549,8 +1603,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], @@ -1728,15 +1782,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, ushort 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; @@ -1752,8 +1957,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; } @@ -1764,11 +1969,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); } @@ -1784,8 +1989,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; @@ -1870,7 +2075,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; } @@ -1880,8 +2085,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/drivers/net/wireless/bcm4329/dhd_custom_gpio.c b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c index f2b7adbed0d3..8c6ec470b8bd 100644 --- a/drivers/net/wireless/bcm4329/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c @@ -20,7 +20,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_custom_gpio.c,v 1.1.4.7 2010/06/03 21:27:48 Exp $ +* $Id: dhd_custom_gpio.c,v 1.1.4.8.4.1 2010/09/02 23:13:16 Exp $ */ @@ -46,11 +46,7 @@ extern void bcm_wlan_power_on(int); int wifi_set_carddetect(int on); int wifi_set_power(int on, unsigned long msec); int wifi_get_irq_number(unsigned long *irq_flags_ptr); -#endif - -#if defined(CONFIG_WIFI_CONTROL_FUNC) -int wifi_set_power(int on, unsigned long msec); -int wifi_set_reset(int on, unsigned long msec); +int wifi_get_mac_addr(unsigned char *buf); #endif #if defined(OOB_INTR_ONLY) @@ -82,7 +78,7 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; } #endif - *irq_flags_ptr = IRQF_TRIGGER_FALLING; + if (dhd_oob_gpio_num < 0) { WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", __FUNCTION__)); @@ -118,10 +114,6 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #endif /* CUSTOMER_HW */ #ifdef CUSTOMER_HW2 wifi_set_power(0, 0); -#endif -#if defined(CONFIG_WIFI_CONTROL_FUNC) - wifi_set_power(0, 0); - wifi_set_reset(0, 0); #endif WL_ERROR(("=========== WLAN placed in RESET ========\n")); break; @@ -134,10 +126,6 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #endif /* CUSTOMER_HW */ #ifdef CUSTOMER_HW2 wifi_set_power(1, 0); -#endif -#if defined(CONFIG_WIFI_CONTROL_FUNC) - wifi_set_power(1, 0); - wifi_set_reset(1, 0); #endif WL_ERROR(("=========== WLAN going back to live ========\n")); break; @@ -155,9 +143,9 @@ dhd_customer_gpio_wlan_ctrl(int onoff) __FUNCTION__)); #ifdef CUSTOMER_HW bcm_wlan_power_on(1); -#endif /* CUSTOMER_HW */ /* Lets customer power to get stable */ - OSL_DELAY(500); + OSL_DELAY(50); +#endif /* CUSTOMER_HW */ break; } } @@ -167,11 +155,16 @@ dhd_customer_gpio_wlan_ctrl(int onoff) int dhd_custom_get_mac_address(unsigned char *buf) { + int ret = 0; + WL_TRACE(("%s Enter\n", __FUNCTION__)); if (!buf) return -EINVAL; /* Customer access to MAC address stored outside of DHD driver */ +#ifdef CUSTOMER_HW2 + ret = wifi_get_mac_addr(buf); +#endif #ifdef EXAMPLE_GET_MAC /* EXAMPLE code */ @@ -181,6 +174,6 @@ dhd_custom_get_mac_address(unsigned char *buf) } #endif /* EXAMPLE_GET_MAC */ - return 0; + return ret; } #endif /* GET_CUSTOM_MAC_ENABLE */ diff --git a/drivers/net/wireless/bcm4329/dhd_dbg.h b/drivers/net/wireless/bcm4329/dhd_dbg.h index 9f09ce7fcc04..9bbd289ce496 100644 --- a/drivers/net/wireless/bcm4329/dhd_dbg.h +++ b/drivers/net/wireless/bcm4329/dhd_dbg.h @@ -27,10 +27,10 @@ #ifndef _dhd_dbg_ #define _dhd_dbg_ -#if 0 || (defined DHD_DEBUG) +#ifdef DHD_DEBUG -#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \ - printf args;} while (0) +#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \ + printf args;} while (0) #define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) #define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) #define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) @@ -58,7 +58,7 @@ #define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) #define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -#else /* (defined BCMDBG) || (defined DHD_DEBUG) */ +#else /* DHD_DEBUG */ #define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0) #define DHD_TRACE(args) @@ -87,7 +87,7 @@ #define DHD_EVENT_ON() 0 #define DHD_BTA_ON() 0 #define DHD_ISCAN_ON() 0 -#endif +#endif /* DHD_DEBUG */ #define DHD_LOG(args) diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c index 34854d903c33..f35ed9cd834c 100644 --- a/drivers/net/wireless/bcm4329/dhd_linux.c +++ b/drivers/net/wireless/bcm4329/dhd_linux.c @@ -22,10 +22,9 @@ * 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 #include #endif @@ -58,8 +57,12 @@ #include #include #include - -#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) +//#include #include struct semaphore wifi_control_sem; @@ -67,8 +70,8 @@ struct semaphore wifi_control_sem; struct dhd_bus *g_bus; static struct wifi_platform_data *wifi_control_data = NULL; -//static struct resource *wifi_irqres = NULL; -#if 0 +static struct resource *wifi_irqres = NULL; + int wifi_get_irq_number(unsigned long *irq_flags_ptr) { if (wifi_irqres) { @@ -81,7 +84,6 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr) return -1; #endif } -#endif int wifi_set_carddetect(int on) { @@ -113,17 +115,29 @@ int wifi_set_reset(int on, unsigned long msec) mdelay(msec); return 0; } + +int wifi_get_mac_addr(unsigned char *buf) +{ + printk("%s\n", __FUNCTION__); + if (!buf) + return -EINVAL; + if (wifi_control_data && wifi_control_data->get_mac_addr) { + return wifi_control_data->get_mac_addr(buf); + } + return -EOPNOTSUPP; +} + static int wifi_probe(struct platform_device *pdev) { struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - printk("## %s\n", __FUNCTION__); -// wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + DHD_TRACE(("## %s\n", __FUNCTION__)); + wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); wifi_control_data = wifi_ctrl; wifi_set_power(1, 0); /* Power On */ - wifi_set_reset(1, 0); + wifi_set_reset(1, 0); /* deactive reset */ wifi_set_carddetect(1); /* CardDetect (0->1) */ up(&wifi_control_sem); @@ -135,11 +149,11 @@ static int wifi_remove(struct platform_device *pdev) struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - printk("## %s\n", __FUNCTION__); + DHD_TRACE(("## %s\n", __FUNCTION__)); wifi_control_data = wifi_ctrl; - - wifi_set_power(0, 0); - wifi_set_reset(0, 0); + + wifi_set_power(0, 0); /* Power Off */ + wifi_set_reset(0, 0); /* active reset */ wifi_set_carddetect(0); /* CardDetect (1->0) */ up(&wifi_control_sem); @@ -153,7 +167,7 @@ static int wifi_suspend(struct platform_device *pdev, pm_message_t state) static int wifi_resume(struct platform_device *pdev) { DHD_TRACE(("##> %s\n", __FUNCTION__)); - return 0; + return 0; } static struct platform_driver wifi_device = { @@ -177,7 +191,7 @@ void wifi_del_dev(void) DHD_TRACE(("## Unregister platform_driver_register\n")); platform_driver_unregister(&wifi_device); } -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) @@ -209,9 +223,12 @@ print_tainted() #if defined(CONFIG_HAS_EARLYSUSPEND) #include 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 { @@ -256,6 +273,19 @@ typedef struct dhd_info { struct semaphore dpc_sem; struct completion dpc_exited; + /* Wakelocks */ +#ifdef CONFIG_HAS_WAKELOCK + struct wake_lock wl_wifi; /* Wifi wakelock */ + struct wake_lock wl_rxwake; /* Wifi rx wakelock */ +#endif + spinlock_t wl_lock; + int wl_count; + int wl_packet; + + int hang_was_sent; + + struct mutex wl_start_lock; + /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -277,10 +307,9 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; -extern int wl_control_wl_start(struct net_device *dev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct semaphore dhd_registration_sem; -#define DHD_REGISTRATION_TIMEOUT 10000 /* msec : allowed time to finished dhd registration */ +#define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */ #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); @@ -335,7 +364,7 @@ module_param(dhd_dpc_prio, int, 0); extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); -/* Contorl fw roaming */ +/* Control fw roaming */ #ifdef CUSTOMER_HW2 uint dhd_roam = 0; #else @@ -346,7 +375,7 @@ uint dhd_roam = 1; uint dhd_radio_up = 1; /* Network inteface name */ -char iface_name[IFNAMSIZ]; +char iface_name[IFNAMSIZ] = "wlan0"; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) @@ -381,7 +410,6 @@ module_param(dhd_idletime, int, 0); uint dhd_poll = FALSE; module_param(dhd_poll, uint, 0); - /* Use interrupts */ uint dhd_intr = TRUE; module_param(dhd_intr, uint, 0); @@ -412,9 +440,11 @@ uint dhd_pktgen_len = 0; module_param(dhd_pktgen_len, uint, 0); #endif - /* Version string to report */ #ifdef DHD_DEBUG +#ifndef SRCBASE +#define SRCBASE "drivers/net/wireless/bcm4329" +#endif #define DHD_COMPILED "\nCompiled in " SRCBASE #else #define DHD_COMPILED @@ -446,21 +476,25 @@ static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_event_msg_t *event_ptr, void **data_ptr); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1 +#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 = { @@ -470,12 +504,27 @@ static struct notifier_block dhd_sleep_pm_notifier = { 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) */ - /* && defined(DHD_GPL) */ +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; */ @@ -484,87 +533,98 @@ 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_os_proto_block(dhd); - if (value) { + 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)); #ifdef CUSTOMER_HW2 - /* Disable build-in roaming to allowed ext supplicant to take of romaing */ + /* Disable build-in roaming to allowed ext supplicant to take of roaming */ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #endif /* CUSTOMER_HW2 */ } 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; + roamvar = dhd_roam; 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) */ @@ -688,7 +748,11 @@ static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) { struct net_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else struct dev_mc_list *mclist; +#endif uint32 allmulti, cnt; wl_ioctl_t ioc; @@ -698,15 +762,19 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ASSERT(dhd && dhd->iflist[ifidx]); dev = dhd->iflist[ifidx]->net; - mclist = dev->mc_list; + + netif_addr_lock_bh(dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + cnt = netdev_mc_count(dev); +#else cnt = dev->mc_count; +#endif + netif_addr_unlock_bh(dev); /* Determine initial value of allmulti flag */ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; /* Send down the multicast list first. */ - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", @@ -721,10 +789,22 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) memcpy(bufp, &cnt, sizeof(cnt)); bufp += sizeof(cnt); - for (cnt = 0; mclist && (cnt < dev->mc_count); cnt++, mclist = mclist->next) { + netif_addr_lock_bh(dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, dev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + cnt--; + } +#else + for (mclist = dev->mc_list;(mclist && (cnt > 0)); cnt--, mclist = mclist->next) { memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); bufp += ETHER_ADDR_LEN; } +#endif + netif_addr_unlock_bh(dev); memset(&ioc, 0, sizeof(ioc)); ioc.cmd = WLC_SET_VAR; @@ -880,7 +960,7 @@ dhd_op_if(dhd_if_t *ifp) break; case WLC_E_IF_DEL: if (ifp->net != NULL) { - DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__)); + DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__)); netif_stop_queue(ifp->net); unregister_netdev(ifp->net); ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ @@ -900,7 +980,7 @@ dhd_op_if(dhd_if_t *ifp) MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); #ifdef SOFTAP if (ifp->net == ap_net_dev) - ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ + ap_net_dev = NULL; /* NULL SOFTAP global as well */ #endif /* SOFTAP */ } } @@ -917,8 +997,11 @@ _dhd_sysioc_thread(void *data) DAEMONIZE("dhd_sysioc"); while (down_interruptible(&dhd->sysioc_sem) == 0) { + dhd_os_start_lock(&dhd->pub); + dhd_os_wake_lock(&dhd->pub); for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { + DHD_TRACE(("%s: interface %d\n",__FUNCTION__, i)); #ifdef SOFTAP in_ap = (ap_net_dev != NULL); #endif /* SOFTAP */ @@ -926,21 +1009,18 @@ _dhd_sysioc_thread(void *data) dhd_op_if(dhd->iflist[i]); #ifdef SOFTAP if (dhd->iflist[i] == NULL) { - DHD_TRACE(("\n\n %s: interface %d just been removed," - "!\n\n", __FUNCTION__, i)); + DHD_TRACE(("%s: interface %d just been removed!\n\n", __FUNCTION__, i)); continue; } - if (in_ap && dhd->set_macaddress) { - DHD_TRACE(("attempt to set MAC for %s in AP Mode," - "blocked. \n", dhd->iflist[i]->net->name)); + if (in_ap && dhd->set_macaddress) { + DHD_TRACE(("attempt to set MAC for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name)); dhd->set_macaddress = FALSE; continue; } if (in_ap && dhd->set_multicast) { - DHD_TRACE(("attempt to set MULTICAST list for %s" - "in AP Mode, blocked. \n", dhd->iflist[i]->net->name)); + DHD_TRACE(("attempt to set MULTICAST list for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name)); dhd->set_multicast = FALSE; continue; } @@ -955,6 +1035,8 @@ _dhd_sysioc_thread(void *data) } } } + dhd_os_wake_unlock(&dhd->pub); + dhd_os_start_unlock(&dhd->pub); } complete_and_exit(&dhd->sysioc_exited, 0); } @@ -968,6 +1050,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) struct sockaddr *sa = (struct sockaddr *)addr; int ifidx; + DHD_TRACE(("%s: Enter\n",__FUNCTION__)); ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return -1; @@ -986,6 +1069,7 @@ dhd_set_multicast_list(struct net_device *dev) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ifidx; + DHD_TRACE(("%s: Enter\n",__FUNCTION__)); ifidx = dhd_net2idx(dhd, dev); if (ifidx == DHD_BAD_IF) return; @@ -1028,7 +1112,6 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) #ifdef BCMDBUS ret = dbus_send_pkt(dhdp->dbus, pktbuf, NULL /* pktinfo */); #else - WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); ret = dhd_bus_txdata(dhdp->bus, pktbuf); #endif /* BCMDBUS */ @@ -1045,16 +1128,19 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + dhd_os_wake_lock(&dhd->pub); + /* Reject if down */ if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); + DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n", + __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); netif_stop_queue(net); /* Send Event when bus down detected during data session */ if (dhd->pub.busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Event RELOAD send up\n", __FUNCTION__)); - wl_iw_send_priv_event(net, "RELOAD"); + DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); + net_os_send_hang_message(net); } + dhd_os_wake_unlock(&dhd->pub); return -ENODEV; } @@ -1062,6 +1148,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) if (ifidx == DHD_BAD_IF) { DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); netif_stop_queue(net); + dhd_os_wake_unlock(&dhd->pub); return -ENODEV; } @@ -1093,13 +1180,14 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); - done: if (ret) dhd->pub.dstats.tx_dropped++; else dhd->pub.tx_packets++; + dhd_os_wake_unlock(&dhd->pub); + /* Return ok: we always eat the packet */ return 0; } @@ -1216,6 +1304,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ } } + dhd_os_wake_lock_timeout_enable(dhdp); } void @@ -1282,7 +1371,6 @@ static int dhd_watchdog_thread(void *data) { dhd_info_t *dhd = (dhd_info_t *)data; - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_WATCHDOG, "dhd_watchdog_thread"); /* This thread doesn't need any user-level access, * so get rid of all our resources @@ -1301,25 +1389,24 @@ dhd_watchdog_thread(void *data) /* Run until signal received */ while (1) { if (down_interruptible (&dhd->watchdog_sem) == 0) { + if (dhd->pub.dongle_reset == FALSE) { - WAKE_LOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); - WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); } /* Count the tick for reference */ dhd->pub.tickcnt++; /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) { + if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - } + + dhd_os_wake_unlock(&dhd->pub); } else break; } - WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_WATCHDOG); complete_and_exit(&dhd->watchdog_exited, 0); } @@ -1328,6 +1415,7 @@ dhd_watchdog(ulong data) { dhd_info_t *dhd = (dhd_info_t *)data; + dhd_os_wake_lock(&dhd->pub); if (dhd->watchdog_pid >= 0) { up(&dhd->watchdog_sem); return; @@ -1342,6 +1430,7 @@ dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd_os_wake_unlock(&dhd->pub); } static int @@ -1349,7 +1438,6 @@ dhd_dpc_thread(void *data) { dhd_info_t *dhd = (dhd_info_t *)data; - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_DPC, "dhd_dpc_thread"); /* This thread doesn't need any user-level access, * so get rid of all our resources */ @@ -1369,22 +1457,21 @@ dhd_dpc_thread(void *data) if (down_interruptible(&dhd->dpc_sem) == 0) { /* Call bus dpc unless it indicated down (then clean stop) */ if (dhd->pub.busstate != DHD_BUS_DOWN) { - WAKE_LOCK(&dhd->pub, WAKE_LOCK_DPC); if (dhd_bus_dpc(dhd->pub.bus)) { up(&dhd->dpc_sem); - WAKE_LOCK_TIMEOUT(&dhd->pub, WAKE_LOCK_TMOUT, 25); } - WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_DPC); + else { + dhd_os_wake_unlock(&dhd->pub); + } } else { dhd_bus_stop(dhd->pub.bus, TRUE); + dhd_os_wake_unlock(&dhd->pub); } } else break; } - WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_DPC); - complete_and_exit(&dhd->dpc_exited, 0); } @@ -1409,6 +1496,7 @@ dhd_sched_dpc(dhd_pub_t *dhdp) { dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_os_wake_lock(dhdp); if (dhd->dpc_pid >= 0) { up(&dhd->dpc_sem); return; @@ -1630,28 +1718,40 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) uint driver = 0; int ifidx; bool is_set_key_cmd; + int ret; + + dhd_os_wake_lock(&dhd->pub); ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - if (ifidx == DHD_BAD_IF) + if (ifidx == DHD_BAD_IF) { + dhd_os_wake_unlock(&dhd->pub); return -1; + } #if defined(CONFIG_WIRELESS_EXT) /* linux wireless extensions */ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { /* may recurse, do NOT lock */ - return wl_iw_ioctl(net, ifr, cmd); + ret = wl_iw_ioctl(net, ifr, cmd); + dhd_os_wake_unlock(&dhd->pub); + return ret; } #endif /* defined(CONFIG_WIRELESS_EXT) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) - return (dhd_ethtool(dhd, (void*)ifr->ifr_data)); + if (cmd == SIOCETHTOOL) { + ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); + dhd_os_wake_unlock(&dhd->pub); + return ret; + } #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - if (cmd != SIOCDEVPRIVATE) + if (cmd != SIOCDEVPRIVATE) { + dhd_os_wake_unlock(&dhd->pub); return -EOPNOTSUPP; + } memset(&ioc, 0, sizeof(ioc)); @@ -1703,9 +1803,8 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } /* send to dongle (must be up, and wl) */ - if ( - (dhd->pub.busstate != DHD_BUS_DATA)) { - DHD_ERROR(("%s DONGLE_DOWN,__FUNCTION__\n", __FUNCTION__)); + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s DONGLE_DOWN\n", __FUNCTION__)); bcmerror = BCME_DONGLE_DOWN; goto done; } @@ -1726,18 +1825,16 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) if (is_set_key_cmd) { dhd_wait_pend8021x(net); } - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_IOCTL, "dhd_ioctl_entry"); - WAKE_LOCK(&dhd->pub, WAKE_LOCK_IOCTL); bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); - WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_IOCTL); - WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_IOCTL); - if (bcmerror == -ETIMEDOUT) { - DHD_ERROR(("%s: Event RELOAD send up\n", __FUNCTION__)); - wl_iw_send_priv_event(net, "RELOAD"); - } done: + if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && + (!dhd->pub.dongle_reset))) { + DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); + net_os_send_hang_message(net); + } + if (!bcmerror && buf && ioc.buf) { if (copy_to_user(ioc.buf, buf, buflen)) bcmerror = -EFAULT; @@ -1746,6 +1843,8 @@ done: if (buf) MFREE(dhd->pub.osh, buf, buflen); + dhd_os_wake_unlock(&dhd->pub); + return OSL_ERROR(bcmerror); } @@ -1778,13 +1877,18 @@ dhd_open(struct net_device *net) #ifdef TOE uint32 toe_ol; #endif - int ifidx = dhd_net2idx(dhd, net); - int32 ret = 0; + int ifidx; + + wl_control_wl_start(net); /* start if needed */ + ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - /* Force start if ifconfig_up gets called before START command */ - wl_control_wl_start(net); + if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) { + DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); + return -1; + } + if (ifidx == 0) { /* do it only for primary eth0 */ @@ -1804,9 +1908,8 @@ dhd_open(struct net_device *net) netif_start_queue(net); dhd->pub.up = 1; - OLD_MOD_INC_USE_COUNT; - return ret; + return 0; } osl_t * @@ -1822,7 +1925,7 @@ dhd_osl_detach(osl_t *osh) DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); } osl_detach(osh); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 up(&dhd_registration_sem); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } @@ -1926,18 +2029,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) strcat(net->name, "%d"); } - - /* we rename the netdevice interface name wlan0 */ - dev_alloc_name(net, "wlan%d"); if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) goto fail; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) net->open = NULL; #else net->netdev_ops = NULL; #endif + init_MUTEX(&dhd->proto_sem); /* Initialize other structure content */ init_waitqueue_head(&dhd->ioctl_resp_wait); @@ -1947,6 +2048,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); + /* Initialize Wakelock stuff */ + spin_lock_init(&dhd->wl_lock); + dhd->wl_count = 0; + dhd->wl_packet = 0; +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); + wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); +#endif + mutex_init(&dhd->wl_start_lock); + /* Link to info module */ dhd->pub.info = dhd; @@ -1967,7 +2078,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) } #endif /* defined(CONFIG_WIRELESS_EXT) */ - /* Set up the watchdog timer */ init_timer(&dhd->timer); dhd->timer.data = (ulong)dhd; @@ -2015,16 +2125,12 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) */ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); -#if defined(CONFIG_WIFI_CONTROL_FUNC) +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) g_bus = bus; #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) register_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - /* && defined(DHD_GPL) */ - /* Init lock suspend to prevent kernel going to suspend */ - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_TMOUT, "dhd_wake_lock"); - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_LINK_DOWN_TMOUT, "dhd_wake_lock_link_dw_event"); #ifdef CONFIG_HAS_EARLYSUSPEND dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; @@ -2060,19 +2166,12 @@ dhd_bus_start(dhd_pub_t *dhdp) /* try to download image and nvram to the dongle */ if (dhd->pub.busstate == DHD_BUS_DOWN) { - WAKE_LOCK_INIT(dhdp, WAKE_LOCK_DOWNLOAD, "dhd_bus_start"); - WAKE_LOCK(dhdp, WAKE_LOCK_DOWNLOAD); if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); - WAKE_UNLOCK(dhdp, WAKE_LOCK_DOWNLOAD); - WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_DOWNLOAD); return -1; } - - WAKE_UNLOCK(dhdp, WAKE_LOCK_DOWNLOAD); - WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_DOWNLOAD); } /* Start the watchdog timer */ @@ -2087,7 +2186,7 @@ dhd_bus_start(dhd_pub_t *dhdp) #if defined(OOB_INTR_ONLY) /* Host registration for OOB interrupt */ if (bcmsdh_register_oob_intr(dhdp)) { - del_timer(&dhd->timer); + del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); return -ENODEV; @@ -2099,7 +2198,7 @@ dhd_bus_start(dhd_pub_t *dhdp) /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { - del_timer(&dhd->timer); + del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); return -ENODEV; @@ -2128,6 +2227,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 */ @@ -2165,7 +2270,7 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in return ret; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) static struct net_device_ops dhd_ops_pri = { .ndo_open = dhd_open, .ndo_stop = dhd_stop, @@ -2173,7 +2278,7 @@ static struct net_device_ops dhd_ops_pri = { .ndo_do_ioctl = dhd_ioctl_entry, .ndo_start_xmit = dhd_start_xmit, .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list + .ndo_set_multicast_list = dhd_set_multicast_list, }; static struct net_device_ops dhd_ops_virt = { @@ -2181,9 +2286,10 @@ static struct net_device_ops dhd_ops_virt = { .ndo_do_ioctl = dhd_ioctl_entry, .ndo_start_xmit = dhd_start_xmit, .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list + .ndo_set_multicast_list = dhd_set_multicast_list, }; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ +#endif + int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { @@ -2194,11 +2300,10 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ASSERT(dhd && dhd->iflist[ifidx]); - net = dhd->iflist[ifidx]->net; - ASSERT(net); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(net); +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) ASSERT(!net->open); net->get_stats = dhd_get_stats; net->do_ioctl = dhd_ioctl_entry; @@ -2211,7 +2316,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) net->netdev_ops = &dhd_ops_virt; #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) net->open = dhd_open; net->stop = dhd_stop; #else @@ -2224,14 +2329,12 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) if (ifidx != 0) { /* for virtual interfaces use the primary MAC */ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - } if (ifidx == 1) { DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__)); /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0X02; /* set bit 2 , - Locally Administered address */ - + temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */ } net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) @@ -2247,7 +2350,6 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #endif /* WIRELESS_EXT > 12 */ #endif /* defined(CONFIG_WIRELESS_EXT) */ - dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen; memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); @@ -2261,7 +2363,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 */ @@ -2271,14 +2373,13 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #endif /* SOFTAP */ #endif /* CONFIG_WIRELESS_EXT */ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) up(&dhd_registration_sem); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ return 0; fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) net->open = NULL; #else net->netdev_ops = NULL; @@ -2306,7 +2407,7 @@ dhd_bus_detach(dhd_pub_t *dhdp) #endif /* defined(OOB_INTR_ONLY) */ /* Clear the watchdog timer */ - del_timer(&dhd->timer); + del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; } } @@ -2326,16 +2427,26 @@ 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 */ + wl_iw_detach(); +#endif for (i = 1; i < DHD_MAX_IFS; i++) if (dhd->iflist[i]) dhd_del_if(dhd, i); + if (dhd->sysioc_pid >= 0) { + KILL_PROC(dhd->sysioc_pid, SIGTERM); + wait_for_completion(&dhd->sysioc_exited); + } + ifp = dhd->iflist[0]; ASSERT(ifp); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) if (ifp->net->open) { #else if (ifp->net->netdev_ops == &dhd_ops_pri) { @@ -2344,66 +2455,54 @@ dhd_detach(dhd_pub_t *dhdp) unregister_netdev(ifp->net); } + if (dhd->watchdog_pid >= 0) + { + KILL_PROC(dhd->watchdog_pid, SIGTERM); + wait_for_completion(&dhd->watchdog_exited); + } - if (dhd->watchdog_pid >= 0) - { - KILL_PROC(dhd->watchdog_pid, SIGTERM); - wait_for_completion(&dhd->watchdog_exited); - } - - if (dhd->dpc_pid >= 0) - { - KILL_PROC(dhd->dpc_pid, SIGTERM); - wait_for_completion(&dhd->dpc_exited); - } - else - tasklet_kill(&dhd->tasklet); - - if (dhd->sysioc_pid >= 0) { - KILL_PROC(dhd->sysioc_pid, SIGTERM); - wait_for_completion(&dhd->sysioc_exited); - } - - dhd_bus_detach(dhdp); + if (dhd->dpc_pid >= 0) + { + KILL_PROC(dhd->dpc_pid, SIGTERM); + wait_for_completion(&dhd->dpc_exited); + } + else + tasklet_kill(&dhd->tasklet); - if (dhdp->prot) - dhd_prot_detach(dhdp); + dhd_bus_detach(dhdp); -#if defined(CONFIG_WIRELESS_EXT) - /* Attach and link in the iw */ - wl_iw_detach(); -#endif + if (dhdp->prot) + dhd_prot_detach(dhdp); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1 - unregister_pm_notifier(&dhd_sleep_pm_notifier); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + unregister_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - /* && defined(DHD_GPL) */ - WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_TMOUT); - WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_LINK_DOWN_TMOUT); - free_netdev(ifp->net); - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); + free_netdev(ifp->net); +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&dhd->wl_wifi); + wake_lock_destroy(&dhd->wl_rxwake); +#endif + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); + MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); + } } } -} -//static void __exit dhd_module_cleanup(void) -void rockchip_wifi_exit_module(void) +void +rockchip_wifi_exit_module(void) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); dhd_bus_unregister(); -#if defined(CONFIG_WIFI_CONTROL_FUNC) +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) wifi_del_dev(); #endif /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } - -//static int __init dhd_module_init(void) -int rockchip_wifi_init_module(void) +int +rockchip_wifi_init_module(void) { int error; @@ -2422,30 +2521,30 @@ int rockchip_wifi_init_module(void) DHD_ERROR(("Invalid module parameters.\n")); return -EINVAL; } while (0); + /* Call customer gpio to turn on power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -#if defined(CONFIG_WIFI_CONTROL_FUNC) +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) sema_init(&wifi_control_sem, 0); error = wifi_add_dev(); if (error) { DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); - goto faild; + goto fail_0; } /* Waiting callback after platform_driver_register is done or exit with error */ - if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { - printk("%s: platform_driver_register timeout\n", __FUNCTION__); - /* renove device */ - wifi_del_dev(); - goto faild; + if (down_timeout(&wifi_control_sem, msecs_to_jiffies(5000)) != 0) { + error = -EINVAL; + DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); + goto fail_1; } #endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) sema_init(&dhd_registration_sem, 0); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +#endif error = dhd_bus_register(); @@ -2453,7 +2552,7 @@ int rockchip_wifi_init_module(void) printf("\n%s\n", dhd_version); else { DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto faild; + goto fail_1; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) /* @@ -2464,25 +2563,36 @@ int rockchip_wifi_init_module(void) if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { error = -EINVAL; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); - dhd_bus_unregister(); + goto fail_2; } #endif return error; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +fail_2: + dhd_bus_unregister(); +#endif +fail_1: +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) + wifi_del_dev(); +fail_0: +#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ -faild: - /* turn off power and exit */ + /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); - return -EINVAL; + + return error; } +//module_init(dhd_module_init); +//module_exit(dhd_module_cleanup); int mv88w8686_if_sdio_init_module(void) { - return rockchip_wifi_init_module(); + return rockchip_wifi_init_module(); } void mv88w8686_if_sdio_exit_module(void) { - rockchip_wifi_exit_module(); + rockchip_wifi_exit_module(); } EXPORT_SYMBOL(rockchip_wifi_init_module); @@ -2490,10 +2600,6 @@ EXPORT_SYMBOL(rockchip_wifi_exit_module); EXPORT_SYMBOL(mv88w8686_if_sdio_init_module); EXPORT_SYMBOL(mv88w8686_if_sdio_exit_module); -//module_init(rockchip_wifi_init_module); -//module_exit(rockchip_wifi_exit_module); - - /* * OS specific functions required to implement DHD driver in OS independent way */ @@ -2506,6 +2612,7 @@ dhd_os_proto_block(dhd_pub_t *pub) down(&dhd->proto_sem); return 1; } + return 0; } @@ -2542,14 +2649,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; @@ -2585,29 +2695,17 @@ dhd_os_wd_timer(void *bus, uint wdtick) /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { - del_timer(&dhd->timer); + del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; save_dhd_watchdog_ms = wdtick; return; } if (wdtick) { - dhd_watchdog_ms = (uint) wdtick; - if (save_dhd_watchdog_ms != dhd_watchdog_ms) { - - if (dhd->wd_timer_valid == TRUE) - /* Stop timer and restart at new value */ - del_timer(&dhd->timer); - - /* Create timer again when watchdog period is - dynamically changed or in the first instance - */ - dhd->timer.expires = jiffies + dhd_watchdog_ms * HZ / 1000; - add_timer(&dhd->timer); - } else { - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - } + dhd_watchdog_ms = (uint)wdtick; + + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); dhd->wd_timer_valid = TRUE; save_dhd_watchdog_ms = wdtick; @@ -2619,7 +2717,6 @@ dhd_os_open_image(char *filename) { struct file *fp; - fp = filp_open(filename, O_RDONLY, 0); /* * 2.6.11 (FC4) supports filp_open() but later revs don't? @@ -2639,7 +2736,6 @@ dhd_os_get_image_block(char *buf, int len, void *image) struct file *fp = (struct file *)image; int rdlen; - if (!image) return 0; @@ -2668,7 +2764,7 @@ dhd_os_sdlock(dhd_pub_t *pub) if (dhd->threads_only) down(&dhd->sdsem); else - spin_lock_bh(&dhd->sdlock); + spin_lock_bh(&dhd->sdlock); } void @@ -2681,7 +2777,7 @@ dhd_os_sdunlock(dhd_pub_t *pub) if (dhd->threads_only) up(&dhd->sdsem); else - spin_unlock_bh(&dhd->sdlock); + spin_unlock_bh(&dhd->sdlock); } void @@ -2775,12 +2871,19 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, #if defined(CONFIG_WIRELESS_EXT) ASSERT(dhd->iflist[*ifidx] != NULL); + + if (ntoh32(event->event_type) == WLC_E_IF) { + DHD_INFO(("<0> interface:%d OP:%d don't pass to wext," + "net_device might not be created yet\n", + *ifidx, ntoh32(event->event_type))); + return bcmerror; + } + ASSERT(dhd->iflist[*ifidx]->net != NULL); if (dhd->iflist[*ifidx]->net) wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); -#endif /* defined(CONFIG_WIRELESS_EXT) */ - +#endif /* defined(CONFIG_WIRELESS_EXT) */ return (bcmerror); } @@ -2797,7 +2900,7 @@ dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) { -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; dhd_os_sdunlock(dhd); wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); @@ -2808,13 +2911,14 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) void dhd_wait_event_wakeup(dhd_pub_t *dhd) { -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; if (waitqueue_active(&dhdinfo->ctrl_wait)) wake_up_interruptible(&dhdinfo->ctrl_wait); #endif return; } + int dhd_dev_reset(struct net_device *dev, uint8 flag) { @@ -2834,6 +2938,65 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) 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) { @@ -2842,6 +3005,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, ushort 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) { @@ -2906,3 +3110,150 @@ exit: return ret; } #endif /* DHD_DEBUG */ + +int dhd_os_wake_lock_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wl_lock, flags); + ret = dhd->wl_packet; +#ifdef CONFIG_HAS_WAKELOCK + if (dhd->wl_packet) + wake_lock_timeout(&dhd->wl_rxwake, HZ); +#endif + dhd->wl_packet = 0; + spin_unlock_irqrestore(&dhd->wl_lock, flags); + } + /* printk("%s: %d\n", __FUNCTION__, ret); */ + return ret; +} + +int net_os_wake_lock_timeout(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_timeout(&dhd->pub); + return ret; +} + +int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wl_lock, flags); + dhd->wl_packet = 1; + spin_unlock_irqrestore(&dhd->wl_lock, flags); + } + /* printk("%s\n",__func__); */ + return 0; +} + +int net_os_wake_lock_timeout_enable(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_timeout_enable(&dhd->pub); + return ret; +} + +int dhd_os_wake_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wl_lock, flags); +#ifdef CONFIG_HAS_WAKELOCK + if (!dhd->wl_count) + wake_lock(&dhd->wl_wifi); +#endif + dhd->wl_count++; + ret = dhd->wl_count; + spin_unlock_irqrestore(&dhd->wl_lock, flags); + } + /* printk("%s: %d\n", __FUNCTION__, ret); */ + return ret; +} + +int net_os_wake_lock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock(&dhd->pub); + return ret; +} + +int dhd_os_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + dhd_os_wake_lock_timeout(pub); + if (dhd) { + spin_lock_irqsave(&dhd->wl_lock, flags); + if (dhd->wl_count) { + dhd->wl_count--; +#ifdef CONFIG_HAS_WAKELOCK + if (!dhd->wl_count) + wake_unlock(&dhd->wl_wifi); +#endif + ret = dhd->wl_count; + } + spin_unlock_irqrestore(&dhd->wl_lock, flags); + } + /* printk("%s: %d\n", __FUNCTION__, ret); */ + return ret; +} + +int net_os_wake_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_unlock(&dhd->pub); + return ret; +} + +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) { + if (!dhd->hang_was_sent) { + dhd->hang_was_sent = 1; + ret = wl_iw_send_priv_event(dev, "HANG"); + } + } + return ret; +} + +void dhd_os_start_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_lock(&dhd->wl_start_lock); +} + +void dhd_os_start_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_unlock(&dhd->wl_start_lock); +} diff --git a/drivers/net/wireless/bcm4329/dhd_proto.h b/drivers/net/wireless/bcm4329/dhd_proto.h index 382785a1ff6b..7ef6929a5bf7 100644 --- a/drivers/net/wireless/bcm4329/dhd_proto.h +++ b/drivers/net/wireless/bcm4329/dhd_proto.h @@ -34,7 +34,7 @@ #include #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/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c index 127260a5ae92..ff1bdedbc9f3 100644 --- a/drivers/net/wireless/bcm4329/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329/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.4.1 2010/09/02 23:13:16 Exp $ */ #include @@ -36,17 +36,11 @@ #include #include #include - #include #include #include -#ifdef DHD_DEBUG -#include -#include -#endif /* DHD_DEBUG */ #include #include - #include #include #include @@ -64,9 +58,12 @@ #include #include -#ifndef DHDSDIO_MEM_DUMP_FNAME -#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" -#endif +#ifdef DHD_DEBUG +#include +#endif /* DHD_DEBUG */ +#ifdef DHD_DEBUG_TRAP +#include +#endif /* DHD_DEBUG_TRAP */ #define QLEN 256 /* bulk rx and tx queue lengths */ #define FCHI (QLEN - 10) @@ -127,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 */ @@ -427,10 +424,10 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start); #endif -#ifdef DHD_DEBUG +#ifdef DHD_DEBUG_TRAP static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size); static int dhdsdio_mem_dump(dhd_bus_t *bus); -#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG_TRAP */ static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); @@ -551,7 +548,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); DHD_INFO(("CLKCTL: set PENDING\n")); bus->clkstate = CLK_PENDING; - return BCME_OK; } else if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ @@ -1298,7 +1294,6 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) bus->ctrl_frame_stat = FALSE; ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, frame, len, NULL, NULL, NULL); - ASSERT(ret != BCME_PENDING); if (ret < 0) { @@ -1372,21 +1367,21 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); -#ifdef DHD_DEBUG +#ifdef DHD_DEBUG_TRAP dhd_os_sdlock(bus->dhd); dhdsdio_checkdied(bus, NULL, 0); dhd_os_sdunlock(bus->dhd); -#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG_TRAP */ } else if (pending == TRUE) { DHD_CTL(("%s: cancelled\n", __FUNCTION__)); return -ERESTARTSYS; } else { DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); -#ifdef DHD_DEBUG +#ifdef DHD_DEBUG_TRAP dhd_os_sdlock(bus->dhd); dhdsdio_checkdied(bus, NULL, 0); dhd_os_sdunlock(bus->dhd); -#endif /* DHD_DEBUG */ +#endif /* DHD_DEBUG_TRAP */ } if (rxlen) @@ -1406,7 +1401,7 @@ enum { IOV_SDCIS, IOV_MEMBYTES, IOV_MEMSIZE, -#ifdef DHD_DEBUG +#ifdef DHD_DEBUG_TRAP IOV_CHECKDIED, #endif IOV_DOWNLOAD, @@ -1459,10 +1454,10 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, -#endif /* DHD_DEBUG */ #endif /* DHD_DEBUG */ +#ifdef DHD_DEBUG_TRAP + {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, +#endif /* DHD_DEBUG_TRAP */ #ifdef SDTEST {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, @@ -1691,7 +1686,7 @@ xfer_done: return bcmerror; } -#ifdef DHD_DEBUG +#ifdef DHD_DEBUG_TRAP static int dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) { @@ -1844,12 +1839,10 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); } -#ifdef DHD_DEBUG if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - /* Mem dump to a file on device */ - dhdsdio_mem_dump(bus); + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); } -#endif /* DHD_DEBUG */ done: if (mbuffer) @@ -1900,17 +1893,22 @@ dhdsdio_mem_dump(dhd_bus_t *bus) } printf("Done\n"); +#ifdef DHD_DEBUG /* free buf before return !!! */ if (write_to_file(bus->dhd, buf, bus->ramsize)) { printf("%s: Error writing to files\n", __FUNCTION__); return -1; } - /* buf free handled in write_to_file, not here */ +#else + MFREE(bus->dhd->osh, buf, size); +#endif return 0; } +#endif /* DHD_DEBUG_TRAP */ +#ifdef DHD_DEBUG #define CONSOLE_LINE_MAX 192 static int @@ -4228,6 +4226,9 @@ clkwait: DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", __FUNCTION__, rxdone, framecnt)); bus->intdis = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(1); +#endif /* (OOB_INTR_ONLY) */ bcmsdh_intr_enable(sdh); } @@ -4362,13 +4363,14 @@ dhdsdio_isr(void *arg) #if defined(SDIO_ISR_THREAD) DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); + dhd_os_wake_lock(bus->dhd); while (dhdsdio_dpc(bus)); + dhd_os_wake_unlock(bus->dhd); #else bus->dpc_sched = TRUE; dhd_sched_dpc(bus->dhd); #endif - } #ifdef SDTEST @@ -4695,8 +4697,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); } } @@ -4955,12 +4955,15 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, /* if firmware path present try to download and bring up bus */ if ((ret = dhd_bus_start(bus->dhd)) != 0) { +#if 1 DHD_ERROR(("%s: failed\n", __FUNCTION__)); goto fail; +#else if (ret == BCME_NOTUP) { DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__)); goto fail; } +#endif } /* Ok, have the per-port tell the stack we're open for business */ if (dhd_net_attach(bus->dhd, 0) != 0) { @@ -5261,7 +5264,6 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ret = dhdsdio_download_firmware(bus, osh, bus->sdh); - return ret; } @@ -5271,12 +5273,13 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) bool ret; /* Download the firmware */ + dhd_os_wake_lock(bus->dhd); dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ret = _dhdsdio_download_firmware(bus) == 0; dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - + dhd_os_wake_unlock(bus->dhd); return ret; } @@ -5805,6 +5808,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhd_os_proto_unblock(dhdp); /* Expect app to have torn down any connection before calling */ /* Stop the bus, disable F2 */ + dhd_os_sdlock(dhdp); + dhd_bus_stop(bus, FALSE); /* Clean tx/rx buffer pointers, detach from the dongle */ @@ -5813,6 +5818,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) bus->dhd->dongle_reset = TRUE; bus->dhd->up = FALSE; + dhd_os_sdunlock(dhdp); + DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); /* App can now remove power from device */ } else @@ -5824,6 +5831,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (bus->dhd->dongle_reset) { /* Turn on WLAN */ + dhd_os_sdlock(dhdp); + /* Reset SD client */ bcmsdh_reset(bus->sdh); @@ -5855,6 +5864,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) bcmerror = BCME_SDIO_ERROR; } else bcmerror = BCME_SDIO_ERROR; + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_NOTDOWN; DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n", diff --git a/drivers/net/wireless/bcm4329/include/bcmdefs.h b/drivers/net/wireless/bcm4329/include/bcmdefs.h index e3c6876f86fa..f4e99461971b 100644 --- a/drivers/net/wireless/bcm4329/include/bcmdefs.h +++ b/drivers/net/wireless/bcm4329/include/bcmdefs.h @@ -29,7 +29,6 @@ #define STATIC static - #define SI_BUS 0 #define PCI_BUS 1 #define PCMCIA_BUS 2 diff --git a/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h index 6ec5874b6187..4e6d1b5bd94f 100644 --- a/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h @@ -28,7 +28,7 @@ #define __BCMSDH_SDMMC_H__ #define sd_err(x) -#define sd_trace(x) +#define sd_trace(x) #define sd_info(x) #define sd_debug(x) #define sd_data(x) diff --git a/drivers/net/wireless/bcm4329/include/bcmspibrcm.h b/drivers/net/wireless/bcm4329/include/bcmspibrcm.h new file mode 100644 index 000000000000..9dce878d11e2 --- /dev/null +++ b/drivers/net/wireless/bcm4329/include/bcmspibrcm.h @@ -0,0 +1,134 @@ +/* + * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer + * + * Copyright (C) 2010, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: bcmspibrcm.h,v 1.4.4.1.4.3.6.1 2008/09/27 17:03:25 Exp $ + */ + +/* global msglevel for debug messages - bitvals come from sdiovar.h */ + +#define sd_err(x) +#define sd_trace(x) +#define sd_info(x) +#define sd_debug(x) +#define sd_data(x) +#define sd_ctrl(x) + +#define sd_log(x) + +#define SDIOH_ASSERT(exp) \ + do { if (!(exp)) \ + printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ + } while (0) + +#define BLOCK_SIZE_F1 64 +#define BLOCK_SIZE_F2 2048 +#define BLOCK_SIZE_F3 2048 + +/* internal return code */ +#define SUCCESS 0 +#undef ERROR +#define ERROR 1 +#define ERROR_UF 2 +#define ERROR_OF 3 + +/* private bus modes */ +#define SDIOH_MODE_SPI 0 + +#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ +#define USE_MULTIBLOCK 0x4 + +struct sdioh_info { + uint cfg_bar; /* pci cfg address for bar */ + uint32 caps; /* cached value of capabilities reg */ + void *bar0; /* BAR0 for PCI Device */ + osl_t *osh; /* osh handler */ + void *controller; /* Pointer to SPI Controller's private data struct */ + + uint lockcount; /* nest count of spi_lock() calls */ + bool client_intr_enabled; /* interrupt connnected flag */ + bool intr_handler_valid; /* client driver interrupt handler valid */ + sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ + void *intr_handler_arg; /* argument to call interrupt handler */ + bool initialized; /* card initialized */ + uint32 target_dev; /* Target device ID */ + uint32 intmask; /* Current active interrupts */ + void *sdos_info; /* Pointer to per-OS private data */ + + uint32 controller_type; /* Host controller type */ + uint8 version; /* Host Controller Spec Compliance Version */ + uint irq; /* Client irq */ + uint32 intrcount; /* Client interrupts */ + uint32 local_intrcount; /* Controller interrupts */ + bool host_init_done; /* Controller initted */ + bool card_init_done; /* Client SDIO interface initted */ + bool polled_mode; /* polling for command completion */ + + bool sd_use_dma; /* DMA on CMD53 */ + bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ + /* Must be on for sd_multiblock to be effective */ + bool use_client_ints; /* If this is false, make sure to restore */ + /* polling hack in wl_linux.c:wl_timer() */ + int adapter_slot; /* Maybe dealing with multiple slots/controllers */ + int sd_mode; /* SD1/SD4/SPI */ + int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ + uint32 data_xfer_count; /* Current transfer */ + uint16 card_rca; /* Current Address */ + uint8 num_funcs; /* Supported funcs on client */ + uint32 card_dstatus; /* 32bit device status */ + uint32 com_cis_ptr; + uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; + void *dma_buf; + ulong dma_phys; + int r_cnt; /* rx count */ + int t_cnt; /* tx_count */ + uint32 wordlen; /* host processor 16/32bits */ + uint32 prev_fun; + uint32 chip; + uint32 chiprev; + bool resp_delay_all; + bool dwordmode; + + struct spierrstats_t spierrstats; +}; + +/************************************************************ + * Internal interfaces: per-port references into bcmspibrcm.c + */ + +/* Global message bits */ +extern uint sd_msglevel; + +/************************************************************** + * Internal interfaces: bcmspibrcm.c references to per-port code + */ + +/* Interrupt (de)registration routines */ +extern int spi_register_irq(sdioh_info_t *sd, uint irq); +extern void spi_free_irq(uint irq, sdioh_info_t *sd); + +/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ +extern void spi_lock(sdioh_info_t *sd); +extern void spi_unlock(sdioh_info_t *sd); + +/* Allocate/init/free per-OS private data */ +extern int spi_osinit(sdioh_info_t *sd); +extern void spi_osfree(sdioh_info_t *sd); + +#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ +#define SPI_RW_FLAG_S 31 +#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ +#define SPI_ACCESS_S 30 +#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ +#define SPI_FUNCTION_S 28 +#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ +#define SPI_REG_ADDR_S 11 +#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ +#define SPI_LEN_S 0 diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h index 114c735fb381..92dc32635a25 100644 --- a/drivers/net/wireless/bcm4329/include/epivers.h +++ b/drivers/net/wireless/bcm4329/include/epivers.h @@ -31,18 +31,18 @@ #define EPI_MINOR_VERSION 218 -#define EPI_RC_NUMBER 245 +#define EPI_RC_NUMBER 248 -#define EPI_INCREMENTAL_NUMBER 0 +#define EPI_INCREMENTAL_NUMBER 6 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 245, 0 +#define EPI_VERSION 4, 218, 248, 6 -#define EPI_VERSION_NUM 0x04daf500 +#define EPI_VERSION_NUM 0x04daf806 -#define EPI_VERSION_STR "4.218.245.0" -#define EPI_ROUTER_VERSION_STR "4.219.245.0" +#define EPI_VERSION_STR "4.218.248.6" +#define EPI_ROUTER_VERSION_STR "4.219.248.6" #endif diff --git a/drivers/net/wireless/bcm4329/include/linuxver.h b/drivers/net/wireless/bcm4329/include/linuxver.h index 6ee5c5872f61..6ed22658a72b 100644 --- a/drivers/net/wireless/bcm4329/include/linuxver.h +++ b/drivers/net/wireless/bcm4329/include/linuxver.h @@ -32,13 +32,9 @@ #include #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #include -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) -#include -#else +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) #include #endif -#endif #include #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) @@ -70,6 +66,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) #undef IP_TOS #endif @@ -429,22 +426,11 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #define CHECKSUM_HW CHECKSUM_PARTIAL #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -#define KILL_PROC(nr, sig) \ -{ \ -struct task_struct *tsk; \ -struct pid *pid; \ -pid = find_get_pid((pid_t)nr); \ -tsk = pid_task(pid, PIDTYPE_PID); \ -if (tsk) send_sig(sig, tsk, 1); \ -} -#else -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 30)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) #define KILL_PROC(pid, sig) \ { \ struct task_struct *tsk; \ - tsk = find_task_by_vpid(pid); \ + tsk = pid_task(find_vpid(pid), PIDTYPE_PID); \ if (tsk) send_sig(sig, tsk, 1); \ } #else @@ -453,7 +439,6 @@ if (tsk) send_sig(sig, tsk, 1); \ kill_proc(pid, sig, 1); \ } #endif -#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #define netdev_priv(dev) dev->priv diff --git a/drivers/net/wireless/bcm4329/include/sbchipc.h b/drivers/net/wireless/bcm4329/include/sbchipc.h index 05b3fd872973..39e5c8d6aed0 100644 --- a/drivers/net/wireless/bcm4329/include/sbchipc.h +++ b/drivers/net/wireless/bcm4329/include/sbchipc.h @@ -1001,7 +1001,6 @@ typedef volatile struct { #define CST4315_CBUCK_MODE_BURST 0x00000400 #define CST4315_CBUCK_MODE_LPBURST 0x00000c00 - #define PMU_MAX_TRANSITION_DLY 15000 diff --git a/drivers/net/wireless/bcm4329/include/spid.h b/drivers/net/wireless/bcm4329/include/spid.h new file mode 100644 index 000000000000..c740296de9af --- /dev/null +++ b/drivers/net/wireless/bcm4329/include/spid.h @@ -0,0 +1,153 @@ +/* + * SPI device spec header file + * + * Copyright (C) 2010, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * $Id: spid.h,v 1.7.10.1.16.3 2009/04/09 19:23:14 Exp $ + */ + +#ifndef _SPI_H +#define _SPI_H + +/* + * Brcm SPI Device Register Map. + * + */ + +typedef volatile struct { + uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ + uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ + uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay + * function selection, command/data error check + */ + uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ + uint16 intr_reg; /* 0x04, Intr status register */ + uint16 intr_en_reg; /* 0x06, Intr mask register */ + uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ + uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ + uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ + uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ + uint32 test_read; /* 0x14, RO 0xfeedbead signature */ + uint32 test_rw; /* 0x18, RW */ + uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ + uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ + uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ + uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ +} spi_regs_t; + +/* SPI device register offsets */ +#define SPID_CONFIG 0x00 +#define SPID_RESPONSE_DELAY 0x01 +#define SPID_STATUS_ENABLE 0x02 +#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ +#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ +#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ +#define SPID_STATUS_REG 0x08 /* 32 bits */ +#define SPID_F1_INFO_REG 0x0C /* 16 bits */ +#define SPID_F2_INFO_REG 0x0E /* 16 bits */ +#define SPID_F3_INFO_REG 0x10 /* 16 bits */ +#define SPID_TEST_READ 0x14 /* 32 bits */ +#define SPID_TEST_RW 0x18 /* 32 bits */ +#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ +#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ + +/* Bit masks for SPID_CONFIG device register */ +#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ +#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ +#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ +#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ +#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ +#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ +#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ + +/* Bit mask for SPID_RESPONSE_DELAY device register */ +#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ + +/* Bit mask for SPID_STATUS_ENABLE device register */ +#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ +#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ +#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ +#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ +#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ +#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ + +/* Bit mask for SPID_RESET_BP device register */ +#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ +#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ +#define RESET_SPI 0x80 /* reset the above enabled logic */ + +/* Bit mask for SPID_INTR_REG device register */ +#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ +#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 +#define F2_F3_FIFO_WR_OVERFLOW 0x0004 +#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ +#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ +#define F2_PACKET_AVAILABLE 0x0020 +#define F3_PACKET_AVAILABLE 0x0040 +#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ +#define MISC_INTR0 0x0100 +#define MISC_INTR1 0x0200 +#define MISC_INTR2 0x0400 +#define MISC_INTR3 0x0800 +#define MISC_INTR4 0x1000 +#define F1_INTR 0x2000 +#define F2_INTR 0x4000 +#define F3_INTR 0x8000 + +/* Bit mask for 32bit SPID_STATUS_REG device register */ +#define STATUS_DATA_NOT_AVAILABLE 0x00000001 +#define STATUS_UNDERFLOW 0x00000002 +#define STATUS_OVERFLOW 0x00000004 +#define STATUS_F2_INTR 0x00000008 +#define STATUS_F3_INTR 0x00000010 +#define STATUS_F2_RX_READY 0x00000020 +#define STATUS_F3_RX_READY 0x00000040 +#define STATUS_HOST_CMD_DATA_ERR 0x00000080 +#define STATUS_F2_PKT_AVAILABLE 0x00000100 +#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 +#define STATUS_F2_PKT_LEN_SHIFT 9 +#define STATUS_F3_PKT_AVAILABLE 0x00100000 +#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 +#define STATUS_F3_PKT_LEN_SHIFT 21 + +/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ +#define F1_ENABLED 0x0001 +#define F1_RDY_FOR_DATA_TRANSFER 0x0002 +#define F1_MAX_PKT_SIZE 0x01FC + +/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ +#define F2_ENABLED 0x0001 +#define F2_RDY_FOR_DATA_TRANSFER 0x0002 +#define F2_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ +#define F3_ENABLED 0x0001 +#define F3_RDY_FOR_DATA_TRANSFER 0x0002 +#define F3_MAX_PKT_SIZE 0x3FFC + +/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ +#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD + +/* Maximum number of I/O funcs */ +#define SPI_MAX_IOFUNCS 4 + +#define SPI_MAX_PKT_LEN (2048*4) + +/* Misc defines */ +#define SPI_FUNC_0 0 +#define SPI_FUNC_1 1 +#define SPI_FUNC_2 2 +#define SPI_FUNC_3 3 + +#define WAIT_F2RXFIFORDY 100 +#define WAIT_F2RXFIFORDY_DELAY 20 + +#endif /* _SPI_H */ diff --git a/drivers/net/wireless/bcm4329/include/wlioctl.h b/drivers/net/wireless/bcm4329/include/wlioctl.h index d346945dec94..345ba34b94c0 100644 --- a/drivers/net/wireless/bcm4329/include/wlioctl.h +++ b/drivers/net/wireless/bcm4329/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/drivers/net/wireless/bcm4329/linux_osl.c b/drivers/net/wireless/bcm4329/linux_osl.c index 242af39e0caa..d00bd1ca291b 100644 --- a/drivers/net/wireless/bcm4329/linux_osl.c +++ b/drivers/net/wireless/bcm4329/linux_osl.c @@ -26,9 +26,7 @@ #define LINUX_OSL -#if defined(CHROMIUMOS_COMPAT_WIRELESS) -#include -#endif + #include #include #include @@ -153,8 +151,10 @@ osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { osl_t *osh; + gfp_t flags; - osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); + flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + osh = kmalloc(sizeof(osl_t), flags); ASSERT(osh); bzero(osh, sizeof(osl_t)); @@ -195,9 +195,9 @@ osl_attach(void *pdev, uint bustype, bool pkttag) STATIC_BUF_TOTAL_LEN))) { printk("can not alloc static buf!\n"); } - else - printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); - + else { + /* printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); */ + } init_MUTEX(&bcm_static_buf->static_sem); @@ -455,8 +455,8 @@ void* osl_malloc(osl_t *osh, uint size) { void *addr; + gfp_t flags; - if (osh) ASSERT(osh->magic == OS_HANDLE_MAGIC); @@ -493,8 +493,8 @@ osl_malloc(osl_t *osh, uint size) } original: #endif - - if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { + flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + if ((addr = kmalloc(size, flags)) == NULL) { if (osh) osh->failed++; return (NULL); @@ -606,8 +606,10 @@ void * osl_pktdup(osl_t *osh, void *skb) { void * p; + gfp_t flags; - if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) + flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; + if ((p = skb_clone((struct sk_buff*)skb, flags)) == NULL) return NULL; diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c index d817dccf89ad..eb8649f4d832 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.c +++ b/drivers/net/wireless/bcm4329/wl_iw.c @@ -21,10 +21,9 @@ * 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.4.13 2010/09/15 03:34:56 Exp $ */ -#include #include #include @@ -88,25 +87,21 @@ typedef const struct si_pub si_t; #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) #include +#include #define WL_IW_USE_ISCAN 1 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1 - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - struct mutex g_wl_ss_scan_lock; -#endif - #if defined(SOFTAP) #define WL_SOFTAP(x) printk x static struct net_device *priv_dev; -static bool ap_cfg_running = FALSE; -static bool ap_fw_loaded = FALSE; +static bool ap_cfg_running = FALSE; +static bool ap_fw_loaded = FALSE; struct net_device *ap_net_dev = NULL; struct semaphore ap_eth_sema; static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap); static int wl_iw_softap_deassoc_stations(struct net_device *dev); -#endif +#endif #define WL_IW_IOCTL_CALL(func_call) \ do { \ @@ -114,6 +109,8 @@ 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_cache_lock; extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen); @@ -163,9 +160,9 @@ static wlc_ssid_t g_specific_ssid; static wlc_ssid_t g_ssid; static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; -static volatile uint g_first_broadcast_scan; - - +static volatile uint g_first_broadcast_scan; +static volatile uint g_first_counter_scans; +#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) @@ -182,16 +179,15 @@ static volatile uint g_first_broadcast_scan; #endif #if defined(WL_IW_USE_ISCAN) -#if !defined(CSCAN) +#if !defined(CSCAN) static void wl_iw_free_ss_cache(void); static int wl_iw_run_ss_cache_timer(int kick_off); -#endif +#endif int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len); #define ISCAN_STATE_IDLE 0 #define ISCAN_STATE_SCANING 1 - #define WLC_IW_ISCAN_MAXLEN 2048 typedef struct iscan_buf { struct iscan_buf * next; @@ -217,12 +213,11 @@ typedef struct iscan_info { char ioctlbuf[WLC_IOCTL_MEDLEN]; #else char ioctlbuf[WLC_IOCTL_SMLEN]; -#endif - +#endif wl_iscan_params_t *iscan_ex_params_p; int iscan_ex_param_size; } iscan_info_t; -#define COEX_DHCP 1 +#define COEX_DHCP 1 static void wl_iw_bt_flag_set(struct net_device *dev, bool set); static void wl_iw_bt_release(void); @@ -263,6 +258,8 @@ wl_iw_set_scan( union iwreq_data *wrqu, char *extra ); + +#ifndef CSCAN static int wl_iw_get_scan( struct net_device *dev, @@ -278,7 +275,7 @@ wl_iw_get_scan_prep( char *extra, short max_size ); - +#endif static void swap_key_from_BE( wl_wsec_key_t *key @@ -324,6 +321,8 @@ dev_wlc_ioctl( return ret; } + net_os_wake_lock(dev); + WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", __FUNCTION__, current->pid, cmd, arg, len)); @@ -336,25 +335,28 @@ dev_wlc_ioctl( strcpy(ifr.ifr_name, dev->name); ifr.ifr_data = (caddr_t) &ioc; - ret = dev_open(dev); if (ret) { WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret)); + net_os_wake_unlock(dev); return ret; } fs = get_fs(); set_fs(get_ds()); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); #else ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -#endif +#endif set_fs(fs); } else { WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__)); } + + net_os_wake_unlock(dev); + return ret; } @@ -399,8 +401,6 @@ dev_wlc_intvar_set_reg( } - - static int dev_wlc_intvar_set( struct net_device *dev, @@ -464,11 +464,7 @@ dev_wlc_bufvar_set( char *name, char *buf, int len) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - char ioctlbuf[MAX_WLIW_IOCTL_LEN]; -#else static char ioctlbuf[MAX_WLIW_IOCTL_LEN]; -#endif uint buflen; buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf)); @@ -476,7 +472,7 @@ dev_wlc_bufvar_set( return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen)); } -#endif +#endif static int @@ -485,11 +481,7 @@ dev_wlc_bufvar_get( char *name, char *buf, int buflen) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - char ioctlbuf[MAX_WLIW_IOCTL_LEN]; -#else static char ioctlbuf[MAX_WLIW_IOCTL_LEN]; -#endif int error; uint len; @@ -614,7 +606,6 @@ wl_iw_get_macaddr( } - static int wl_iw_set_country( struct net_device *dev, @@ -629,15 +620,15 @@ wl_iw_set_country( int country_offset; int country_code_size; + WL_TRACE(("%s\n", __FUNCTION__)); memset(country_code, 0, sizeof(country_code)); - country_offset = strcspn(extra, " "); country_code_size = strlen(extra) - country_offset; if (country_offset != 0) { - strncpy(country_code, extra + country_offset +1, + strncpy(country_code, extra + country_offset + 1, MIN(country_code_size, sizeof(country_code))); @@ -668,11 +659,11 @@ wl_iw_set_power_mode( { int error = 0; char *p = extra; - static int pm = PM_FAST; - int pm_local = PM_OFF; + static int pm = PM_FAST; + int pm_local = PM_OFF; char powermode_val = 0; - strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1); + strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1); if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { @@ -680,15 +671,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) { - WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); + /* 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")); } @@ -698,7 +694,37 @@ wl_iw_set_power_mode( return error; } -#endif +#endif + +static int +wl_iw_get_power_mode( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error; + char *p = extra; + int pm_local = PM_FAST; + + error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local)); + if (!error) { + WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local)); + if (pm_local == PM_OFF) + pm_local = 1; /* Active */ + else + pm_local = 0; /* Auto */ + p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local); + } + else { + WL_TRACE(("%s: Error = %d\n", __func__, error)); + p += snprintf(p, MAX_WX_STRING, "FAIL"); + } + wrqu->data.length = p - extra + 1; + return error; +} + static int wl_iw_set_btcoex_dhcp( struct net_device *dev, @@ -727,20 +753,18 @@ wl_iw_set_btcoex_dhcp( char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; #ifndef CUSTOMER_HW2 uint32 temp1, temp2; -#endif +#endif - -#ifdef CUSTOMER_HW2 - strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") +1, 1); +#ifdef CUSTOMER_HW2 + strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") + 1, 1); #else - strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1); + strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1); #endif if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); - if ((saved_status == FALSE) && #ifndef CUSTOMER_HW2 (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && @@ -752,24 +776,16 @@ wl_iw_set_btcoex_dhcp( WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", \ saved_reg66, saved_reg41, saved_reg68)); - #ifndef CUSTOMER_HW2 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); #endif - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg66va_dhcp_on[0], \ - sizeof(buf_reg66va_dhcp_on)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg41va_dhcp_on[0], \ - sizeof(buf_reg41va_dhcp_on)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg68va_dhcp_on[0], \ - sizeof(buf_reg68va_dhcp_on)); - + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg66va_dhcp_on[0], sizeof(buf_reg66va_dhcp_on)); + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg41va_dhcp_on[0], sizeof(buf_reg41va_dhcp_on)); + dev_wlc_bufvar_set(dev, "btc_params", \ + (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on)); #ifndef CUSTOMER_HW2 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 12, &temp1)) && (!dev_wlc_intvar_get_reg(dev, "btc_params", 13, &temp2))) @@ -790,31 +806,26 @@ wl_iw_set_btcoex_dhcp( WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); } } -#ifdef CUSTOMER_HW2 +#ifdef CUSTOMER_HW2 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { #else else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { #endif - WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); - #ifndef CUSTOMER_HW2 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); #endif - WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); if (g_bt->timer_on) { g_bt->timer_on = 0; del_timer_sync(&g_bt->timer); } - dev_wlc_bufvar_set(dev, "btc_flags", \ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); - if (saved_status) { regaddr = 66; dev_wlc_intvar_set_reg(dev, "btc_params", \ @@ -827,7 +838,6 @@ wl_iw_set_btcoex_dhcp( (char *)®addr, (char *)&saved_reg68); } saved_status = FALSE; - } else { WL_ERROR(("Unkwown yet power setting, ignored\n")); @@ -840,6 +850,36 @@ wl_iw_set_btcoex_dhcp( return error; } +static int +wl_iw_set_suspend( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int suspend_flag; + int ret_now; + int ret = 0; + + 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 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) { @@ -876,7 +916,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; @@ -886,6 +926,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; } @@ -902,6 +1027,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)); @@ -909,6 +1036,8 @@ wl_iw_get_band( wrqu->data.length = p - extra + 1; } + + net_os_wake_unlock(dev); return error; } @@ -923,11 +1052,13 @@ wl_iw_set_band( { int error = -1; char *p = extra; - char band; + 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)) { @@ -938,20 +1069,255 @@ 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, 0x01, 0x00, + 'S', + 0x04, + 'B', 'R', 'C', 'M', + 'S', + 0x04, + 'G', 'O', 'O', 'G', + 'T', + 0x00, + 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(short), &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_wext_rssi( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + static int rssi = 0; + static wlc_ssid_t ssid = {0}; + int error = 0; + 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); + + error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); + if (!error) { + ssid.SSID_len = dtoh32(ssid.SSID_len); + wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + } + } + + wrqu->sens.value = -rssi; + + printk("%s rssi = %d\n", __func__, rssi); + + net_os_wake_unlock(dev); + return error; +} + static int wl_iw_get_rssi( struct net_device *dev, @@ -967,21 +1333,30 @@ 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); error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); - - ssid.SSID_len = dtoh32(ssid.SSID_len); + if (!error) { + ssid.SSID_len = dtoh32(ssid.SSID_len); + wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + } } - wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } @@ -1003,6 +1378,7 @@ wl_iw_send_priv_event( strcpy(extra, flag); wrqu.data.length = strlen(extra); wireless_send_event(dev, cmd, &wrqu, extra); + net_os_wake_lock_timeout_enable(dev); WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); return 0; @@ -1012,10 +1388,10 @@ wl_iw_send_priv_event( int wl_control_wl_start(struct net_device *dev) { - int ret = 0; wl_iw_t *iw; + int ret = 0; - WL_ERROR(("Enter %s \n", __FUNCTION__)); + WL_TRACE(("Enter %s \n", __FUNCTION__)); if (!dev) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); @@ -1023,7 +1399,7 @@ wl_control_wl_start(struct net_device *dev) } iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK(iw->pub); + dhd_os_start_lock(iw->pub); if (g_onoff == G_WLAN_SET_OFF) { dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); @@ -1042,21 +1418,23 @@ wl_control_wl_start(struct net_device *dev) g_onoff = G_WLAN_SET_ON; } - WL_ERROR(("Exited %s \n", __FUNCTION__)); + WL_TRACE(("Exited %s \n", __FUNCTION__)); - MUTEX_UNLOCK(iw->pub); + dhd_os_start_unlock(iw->pub); return ret; } + + static int wl_iw_control_wl_off( struct net_device *dev, struct iw_request_info *info ) { - int ret = 0; wl_iw_t *iw; + int ret = 0; - WL_ERROR(("Enter %s\n", __FUNCTION__)); + WL_TRACE(("Enter %s\n", __FUNCTION__)); if (!dev) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); @@ -1064,47 +1442,46 @@ wl_iw_control_wl_off( } iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK(iw->pub); + dhd_os_start_lock(iw->pub); #ifdef SOFTAP ap_cfg_running = FALSE; - -#endif +#endif if (g_onoff == G_WLAN_SET_ON) { g_onoff = G_WLAN_SET_OFF; - #if defined(WL_IW_USE_ISCAN) g_iscan->iscan_state = ISCAN_STATE_IDLE; -#endif +#endif dhd_dev_reset(dev, 1); #if defined(WL_IW_USE_ISCAN) #if !defined(CSCAN) - wl_iw_free_ss_cache(); wl_iw_run_ss_cache_timer(0); - + g_ss_cache_ctrl.m_link_down = 1; -#endif +#endif memset(g_scan, 0, G_SCAN_RESULTS); g_scan_specified_ssid = 0; - + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; -#endif + g_first_counter_scans = 0; +#endif #if defined(BCMLXSDMMC) 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"); - } - MUTEX_UNLOCK(iw->pub); + dhd_os_start_unlock(iw->pub); WL_TRACE(("Exited %s\n", __FUNCTION__)); @@ -1125,7 +1502,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); @@ -1133,7 +1509,6 @@ wl_iw_control_wl_on( #else wl_iw_iscan_set_scan_broadcast_prep(dev, 0); #endif -#endif WL_TRACE(("Exited %s \n", __FUNCTION__)); @@ -1142,18 +1517,18 @@ wl_iw_control_wl_on( #ifdef SOFTAP static struct ap_profile my_ap; -static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); +static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); static int get_assoc_sta_list(struct net_device *dev, char *buf, int len); static int set_ap_mac_list(struct net_device *dev, char *buf); -#define PTYPE_STRING 0 -#define PTYPE_INTDEC 1 -#define PTYPE_INTHEX 2 -#define PTYPE_STR_HEX 3 +#define PTYPE_STRING 0 +#define PTYPE_INTDEC 1 +#define PTYPE_INTHEX 2 +#define PTYPE_STR_HEX 3 int get_parmeter_from_string( char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); -#endif +#endif int hex2num(char c) { @@ -1209,18 +1584,15 @@ int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) memset(sub_cmd, 0, sizeof(sub_cmd)); memset(ap_cfg, 0, sizeof(struct ap_profile)); - if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, SSID_LEN) != 0) { - return -1; + return -1; } if (strncmp(sub_cmd, "AP_CFG", 6)) { - WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd)); + WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd)); return -1; } - - ret = get_parmeter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN); ret |= get_parmeter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN); @@ -1235,15 +1607,14 @@ int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) return ret; } -#endif - +#endif #ifdef SOFTAP static int iwpriv_set_ap_config(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *ext) + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) { int res = 0; char *extra = NULL; @@ -1253,7 +1624,6 @@ static int iwpriv_set_ap_config(struct net_device *dev, info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length)); - if (wrqu->data.length != 0) { char *str_ptr; @@ -1271,8 +1641,6 @@ static int iwpriv_set_ap_config(struct net_device *dev, memset(ap_cfg, 0, sizeof(struct ap_profile)); - - str_ptr = extra; if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) { @@ -1282,9 +1650,8 @@ static int iwpriv_set_ap_config(struct net_device *dev, } } else { - - WL_ERROR(("IWPRIV argument len = 0 \n")); - return -1; + WL_ERROR(("IWPRIV argument len = 0 \n")); + return -1; } if ((res = set_ap_cfg(dev, ap_cfg)) < 0) @@ -1294,15 +1661,14 @@ static int iwpriv_set_ap_config(struct net_device *dev, return res; } -#endif - +#endif #ifdef SOFTAP static int iwpriv_get_assoc_list(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *p_iwrq, - char *extra) + struct iw_request_info *info, + union iwreq_data *p_iwrq, + char *extra) { int i, ret = 0; char mac_buf[256]; @@ -1326,17 +1692,15 @@ static int iwpriv_get_assoc_list(struct net_device *dev, get_assoc_sta_list(dev, mac_buf, 256); WL_TRACE((" got %d stations\n", sta_maclist->count)); - memset(mac_lst, 0, sizeof(mac_lst)); p_mac_str = mac_lst; for (i = 0; i < 8; i++) { - struct ether_addr * id = &sta_maclist->ea[i]; + struct ether_addr *id = &sta_maclist->ea[i]; WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i)); print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0); - p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, "Mac[%d]=%02X:%02X:%02X:%02X:%02X:%02X\n", i, id->octet[0], id->octet[1], id->octet[2], @@ -1356,23 +1720,23 @@ static int iwpriv_get_assoc_list(struct net_device *dev, } } - WL_ERROR(("Exited %s \n", __FUNCTION__)); + WL_TRACE(("Exited %s \n", __FUNCTION__)); return ret; } -#endif +#endif #ifdef SOFTAP static int iwpriv_set_mac_filters(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *ext) + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) { int i, ret = -1; - char * extra = NULL; + char *extra = NULL; u8 macfilt[8][6]; - int mac_cnt = 0; + int mac_cnt = 0; char sub_cmd[16]; WL_TRACE((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \ @@ -1398,18 +1762,16 @@ static int iwpriv_set_mac_filters(struct net_device *dev, memset(macfilt, 0, sizeof(macfilt)); memset(sub_cmd, 0, sizeof(sub_cmd)); - str_ptr = extra; - - if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, 15) != 0) { - goto exit_proc; - } + if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, 15) != 0) { + goto exit_proc; + } #define MAC_FILT_MAX 8 - + if (strncmp(sub_cmd, "MAC_FLT_W", strlen("MAC_FLT_W"))) { - WL_ERROR(("ERROR: sub_cmd:%s != 'MAC_FLT_W'!\n", sub_cmd)); + WL_ERROR(("ERROR: sub_cmd:%s != 'MAC_FLT_W'!\n", sub_cmd)); goto exit_proc; } @@ -1424,36 +1786,35 @@ static int iwpriv_set_mac_filters(struct net_device *dev, goto exit_proc; } - for (i=0; i< mac_cnt; i++) - if (get_parmeter_from_string(&str_ptr, "MAC=", - PTYPE_STR_HEX, macfilt[i], 12) != 0) { - WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i)); - goto exit_proc; + for (i = 0; i < mac_cnt; i++) { + if (get_parmeter_from_string(&str_ptr, "MAC=", + PTYPE_STR_HEX, macfilt[i], 12) != 0) { + WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i)); + goto exit_proc; + } } for (i = 0; i < mac_cnt; i++) { - WL_SOFTAP(("mac_filt[%d]:", i)); - print_buf(macfilt[i], 6, 0); + WL_SOFTAP(("mac_filt[%d]:", i)); + print_buf(macfilt[i], 6, 0); } - wrqu->data.pointer = NULL; wrqu->data.length = 0; ret = 0; } else { - - WL_ERROR(("IWPRIV argument len is 0\n")); - return -1; + WL_ERROR(("IWPRIV argument len is 0\n")); + return -1; } exit_proc: kfree(extra); return ret; } -#endif +#endif -#endif +#endif #if WIRELESS_EXT < 13 struct iw_request_info @@ -1463,9 +1824,9 @@ struct iw_request_info }; typedef int (*iw_handler)(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, - char *extra); + struct iw_request_info *info, + void *wrqu, + char *extra); #endif static int @@ -1525,7 +1886,7 @@ wl_iw_set_freq( int error, chan; uint sf = 0; - WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name)); + WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name)); #if defined(SOFTAP) if (ap_cfg_running) { @@ -1557,10 +1918,10 @@ wl_iw_set_freq( chan = wf_mhz2channel(fwrq->m, sf); } chan = htod32(chan); - if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) return error; + g_wl_iw_params.target_channel = chan; return -EINPROGRESS; } @@ -1581,7 +1942,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; @@ -1685,10 +2045,8 @@ wl_iw_get_range( dwrq->length = sizeof(struct iw_range); memset(range, 0, sizeof(range)); - range->min_nwid = range->max_nwid = 0; - list->count = htod32(MAXCHANNEL); if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) { kfree(channels); @@ -1708,7 +2066,6 @@ wl_iw_get_range( } range->num_frequency = range->num_channels = i; - range->max_qual.qual = 5; range->max_qual.level = 0x100 - 200; @@ -1726,7 +2083,6 @@ wl_iw_get_range( range->avg_qual.noise = 0x100 - 75; #endif - if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) { kfree(channels); return error; @@ -1765,7 +2121,6 @@ wl_iw_get_range( } } - if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) { kfree(channels); return error; @@ -1776,7 +2131,6 @@ wl_iw_get_range( else range->throughput = 1500000; - range->min_rts = 0; range->max_rts = 2347; range->min_frag = 256; @@ -1793,7 +2147,6 @@ wl_iw_get_range( #endif range->encoding_size[3] = AES_KEY_SIZE; - range->min_pmp = 0; range->max_pmp = 0; range->min_pmt = 0; @@ -1801,7 +2154,6 @@ wl_iw_get_range( range->pmp_flags = 0; range->pm_capa = 0; - range->num_txpower = 2; range->txpower[0] = 1; range->txpower[1] = 255; @@ -1811,7 +2163,6 @@ wl_iw_get_range( range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 19; - range->retry_capa = IW_RETRY_LIMIT; range->retry_flags = IW_RETRY_LIMIT; range->r_time_flags = 0; @@ -1831,9 +2182,8 @@ wl_iw_get_range( range->enc_capa |= IW_ENC_CAPA_WPA2; #endif - IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); @@ -1919,6 +2269,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, @@ -1929,6 +2314,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)); @@ -1950,16 +2336,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; @@ -2026,6 +2422,7 @@ wl_iw_mlme( } #endif +#ifndef WL_IW_USE_ISCAN static int wl_iw_get_aplist( struct net_device *dev, @@ -2046,7 +2443,6 @@ wl_iw_get_aplist( if (!extra) return -EINVAL; - list = kmalloc(buflen, GFP_KERNEL); if (!list) return -ENOMEM; @@ -2061,7 +2457,7 @@ wl_iw_get_aplist( list->version = dtoh32(list->version); list->count = dtoh32(list->count); if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + WL_ERROR(("%s: list->version %d != WL_BSS_INFO_VERSION\n", \ __FUNCTION__, list->version)); kfree(list); return -EINVAL; @@ -2069,21 +2465,23 @@ wl_iw_get_aplist( for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - buflen)); - + if ((dtoh32(bi->length) > buflen) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + buflen))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + kfree(list); + return -E2BIG; + } + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else @@ -2100,9 +2498,9 @@ wl_iw_get_aplist( dwrq->flags = 1; } - return 0; } +#endif #ifdef WL_IW_USE_ISCAN static int @@ -2128,7 +2526,8 @@ wl_iw_iscan_get_aplist( return -EINVAL; if ((!iscan) || (iscan->sysioc_pid < 0)) { - return wl_iw_get_aplist(dev, info, dwrq, extra); + WL_ERROR(("%s error\n", __FUNCTION__)); + return 0; } buf = iscan->list_hdr; @@ -2145,21 +2544,22 @@ wl_iw_iscan_get_aplist( for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - WLC_IW_ISCAN_MAXLEN)); - + if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + return -E2BIG; + } + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); qual[dwrq->length].noise = 0x100 + bi->phy_noise; - #if WIRELESS_EXT > 18 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; #else @@ -2175,7 +2575,6 @@ wl_iw_iscan_get_aplist( dwrq->flags = 1; } - return 0; } @@ -2220,8 +2619,11 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); - (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \ - iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)); + if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \ + iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { + WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); + err = -1; + } return err; } @@ -2233,7 +2635,7 @@ wl_iw_timerfunc(ulong data) if (iscan) { iscan->timer_on = 0; if (iscan->iscan_state != ISCAN_STATE_IDLE) { - WL_TRACE(("timer trigger\n")); + WL_SCAN(("timer trigger\n")); up(&iscan->sysioc_sem); } } @@ -2259,9 +2661,9 @@ 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_SCAN_SET(); + mutex_lock(&wl_cache_lock); if (iscan->list_cur) { buf = iscan->list_cur; iscan->list_cur = buf->next; @@ -2271,7 +2673,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) if (!buf) { WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \ __FUNCTION__)); - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); return WL_SCAN_RESULTS_NO_MEM; } buf->next = NULL; @@ -2294,21 +2696,26 @@ 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_TRACE(("results->count = %d\n", results->count)); - - WL_TRACE(("results->buflen = %d\n", results->buflen)); - status = dtoh32(list_buf->status); - MUTEX_UNLOCK_WL_SCAN_SET(); + 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; } @@ -2318,13 +2725,12 @@ static void wl_iw_force_specific_scan(iscan_info_t *iscan) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif - (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)); - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); #endif } + static void wl_iw_send_scan_complete(iscan_info_t *iscan) { #ifndef SANDGATE2G @@ -2332,36 +2738,38 @@ 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")); + if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; + WL_TRACE(("Send Event ISCAN complete\n")); #endif } + static int _iscan_sysioc_thread(void *data) { uint32 status; iscan_info_t *iscan = (iscan_info_t *)data; static bool iscan_pass_abort = FALSE; + DAEMONIZE("iscan_sysioc"); status = WL_SCAN_RESULTS_PARTIAL; while (down_interruptible(&iscan->sysioc_sem) == 0) { + net_os_wake_lock(iscan->dev); + #if defined(SOFTAP) - if (ap_cfg_running) { - WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__)); - continue; + WL_SCAN(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__)); + net_os_wake_unlock(iscan->dev); + continue; } -#endif +#endif + if (iscan->timer_on) { - del_timer(&iscan->timer); iscan->timer_on = 0; + del_timer_sync(&iscan->timer); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -2371,8 +2779,9 @@ _iscan_sysioc_thread(void *data) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); #endif - if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) { - WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status)); + + if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) { + WL_SCAN(("%s Get results from specific scan status=%d\n", __FUNCTION__, status)); wl_iw_send_scan_complete(iscan); iscan_pass_abort = FALSE; status = -1; @@ -2380,32 +2789,32 @@ _iscan_sysioc_thread(void *data) switch (status) { case WL_SCAN_RESULTS_PARTIAL: - WL_TRACE(("iscanresults incomplete\n")); + WL_SCAN(("iscanresults incomplete\n")); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif - + wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); #endif - + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); iscan->timer_on = 1; break; case WL_SCAN_RESULTS_SUCCESS: - WL_TRACE(("iscanresults complete\n")); + WL_SCAN(("iscanresults complete\n")); iscan->iscan_state = ISCAN_STATE_IDLE; wl_iw_send_scan_complete(iscan); break; case WL_SCAN_RESULTS_PENDING: - WL_TRACE(("iscanresults pending\n")); - + WL_SCAN(("iscanresults pending\n")); + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); iscan->timer_on = 1; break; case WL_SCAN_RESULTS_ABORTED: - WL_TRACE(("iscanresults aborted\n")); + WL_SCAN(("iscanresults aborted\n")); iscan->iscan_state = ISCAN_STATE_IDLE; if (g_scan_specified_ssid == 0) wl_iw_send_scan_complete(iscan); @@ -2415,19 +2824,22 @@ _iscan_sysioc_thread(void *data) } break; case WL_SCAN_RESULTS_NO_MEM: - WL_TRACE(("iscanresults can't alloc memory: skip\n")); + WL_SCAN(("iscanresults can't alloc memory: skip\n")); iscan->iscan_state = ISCAN_STATE_IDLE; break; default: - WL_TRACE(("iscanresults returned unknown status %d\n", status)); + WL_SCAN(("iscanresults returned unknown status %d\n", status)); break; - } + } + + net_os_wake_unlock(iscan->dev); } if (iscan->timer_on) { - del_timer(&iscan->timer); iscan->timer_on = 0; + del_timer_sync(&iscan->timer); } + complete_and_exit(&iscan->sysioc_exited, 0); } #endif @@ -2472,7 +2884,7 @@ wl_iw_free_ss_cache(void) WL_TRACE(("%s called\n", __FUNCTION__)); - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; @@ -2483,7 +2895,7 @@ wl_iw_free_ss_cache(void) kfree(cur); } *spec_scan_head = NULL; - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); } @@ -2529,7 +2941,7 @@ wl_iw_reset_ss_cache(void) wl_iw_ss_cache_t *node, *prev, *cur; wl_iw_ss_cache_t **spec_scan_head; - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -2556,7 +2968,7 @@ wl_iw_reset_ss_cache(void) prev = node; node = node->next; } - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); } @@ -2569,13 +2981,13 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) wl_bss_info_t *bi = NULL; int i; - if (!ss_list->count) { return 0; } - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; + for (i = 0; i < ss_list->count; i++) { node = *spec_scan_head; @@ -2600,7 +3012,9 @@ 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) { - MUTEX_UNLOCK_WL_SCAN_SET(); + WL_ERROR(("Memory alloc failure %d\n", \ + bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)); + mutex_unlock(&wl_cache_lock); return -ENOMEM; } @@ -2617,9 +3031,8 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) prev->next = leaf; } } - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); return 0; - } @@ -2630,7 +3043,7 @@ __u16 *merged_len) wl_iw_ss_cache_t *node; wl_scan_results_t *list_merge; - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); node = g_ss_cache_ctrl.m_cache_head; for (;node;) { list_merge = (wl_scan_results_t *)node; @@ -2645,7 +3058,7 @@ __u16 *merged_len) } node = node->next; } - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); return 0; } @@ -2657,7 +3070,7 @@ wl_iw_delete_bss_from_ss_cache(void *addr) wl_iw_ss_cache_t *node, *prev; wl_iw_ss_cache_t **spec_scan_head; - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -2680,12 +3093,11 @@ wl_iw_delete_bss_from_ss_cache(void *addr) } memset(addr, 0, ETHER_ADDR_LEN); - MUTEX_UNLOCK_WL_SCAN_SET(); + mutex_unlock(&wl_cache_lock); return 0; - } -#endif +#endif static int @@ -2697,30 +3109,25 @@ wl_iw_set_scan( ) { int error; - WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); - + WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); #if defined(CSCAN) - WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); - return -EINVAL; + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); + return -EINVAL; #endif #if defined(SOFTAP) - if (ap_cfg_running) { WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); return 0; } -#endif +#endif - if (g_onoff == G_WLAN_SET_OFF) return 0; - memset(&g_specific_ssid, 0, sizeof(g_specific_ssid)); #ifndef WL_IW_USE_ISCAN - g_scan_specified_ssid = 0; #endif @@ -2730,7 +3137,6 @@ wl_iw_set_scan( if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { - WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n", \ __FUNCTION__, req->essid, \ g_first_broadcast_scan)); @@ -2739,7 +3145,6 @@ wl_iw_set_scan( if (g_scan_specified_ssid) { WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n", \ __FUNCTION__, req->essid)); - return -EBUSY; } else { @@ -2757,7 +3162,6 @@ 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; return -EBUSY; } @@ -2772,8 +3176,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__)); @@ -2782,7 +3184,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) @@ -2814,6 +3215,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, @@ -2824,41 +3226,47 @@ 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)); #if defined(CSCAN) - WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); - return -EINVAL; -#endif + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); + 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); + WL_ERROR(("%s error\n", __FUNCTION__)); + 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)); #if WIRELESS_EXT > 17 @@ -2867,35 +3275,47 @@ wl_iw_iscan_set_scan( if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { int as = 0; struct iw_scan_req *req = (struct iw_scan_req *)extra; -#if !defined(CSCAN) - 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; - } -#endif ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); memcpy(ssid.SSID, req->essid, ssid.SSID_len); 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; } } } #endif +#if !defined(CSCAN) + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { + + WL_ERROR(("%s Clean up First scan flag which is %d\n", \ + __FUNCTION__, g_first_broadcast_scan)); + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; + } + else { + WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", \ + __FUNCTION__, g_first_counter_scans)); + ret = -EBUSY; + goto set_scan_end; + } + } +#endif + wl_iw_iscan_set_scan_broadcast_prep(dev, 0); - return 0; +set_scan_end: + net_os_wake_unlock(dev); + return ret; } #endif @@ -2903,17 +3323,13 @@ wl_iw_iscan_set_scan( static bool ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) { - - uint8 *ie = *wpaie; - if ((ie[1] >= 6) && !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { return TRUE; } - ie += ie[1] + 2; *tlvs_len -= (int)(ie - *tlvs); @@ -2925,17 +3341,13 @@ ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) static bool ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) { - - uint8 *ie = *wpsie; - if ((ie[1] >= 4) && !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { return TRUE; } - ie += ie[1] + 2; *tlvs_len -= (int)(ie - *tlvs); @@ -3055,6 +3467,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, return 0; } +#ifndef CSCAN static uint wl_iw_get_scan_prep( wl_scan_results_t *list, @@ -3068,9 +3481,10 @@ wl_iw_get_scan_prep( char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value; int ret = 0; - ASSERT(list); - - + if (!list) { + WL_ERROR(("%s: Null list pointer",__FUNCTION__)); + return ret; + } for (i = 0; i < list->count && i < IW_MAX_AP; i++) { @@ -3078,13 +3492,12 @@ wl_iw_get_scan_prep( WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ __FUNCTION__, list->version)); return ret; - } + } bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID)); - iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); @@ -3095,7 +3508,6 @@ wl_iw_get_scan_prep( iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -3105,7 +3517,6 @@ wl_iw_get_scan_prep( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? @@ -3113,17 +3524,14 @@ wl_iw_get_scan_prep( iwe.u.freq.e = 6; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); - iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); iwe.u.qual.noise = 0x100 + bi->phy_noise; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - - wl_iw_handle_scanresults_ies(&event, end, info, bi); + wl_iw_handle_scanresults_ies(&event, end, info, bi); - iwe.cmd = SIOCGIWENCODE; if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -3132,16 +3540,14 @@ wl_iw_get_scan_prep( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - if (bi->rateset.count) { if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) { value = event + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; - + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { - iwe.u.bitrate.value = - (bi->rateset.rates[j] & 0x7f) * 500000; + iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, IW_EV_PARAM_LEN); } @@ -3173,7 +3579,7 @@ wl_iw_get_scan( uint buflen_from_user = dwrq->length; uint len = G_SCAN_RESULTS; __u16 len_ret = 0; -#if !defined(CSCAN) +#if !defined(CSCAN) __u16 merged_len = 0; #endif #if defined(WL_IW_USE_ISCAN) @@ -3181,9 +3587,8 @@ wl_iw_get_scan( iscan_buf_t * p_buf; #if !defined(CSCAN) uint32 counter = 0; -#endif -#endif - +#endif +#endif WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user)); if (!extra) { @@ -3198,7 +3603,7 @@ wl_iw_get_scan( if (ci.scan_channel) return -EAGAIN; -#if !defined(CSCAN) +#if !defined(CSCAN) if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); g_ss_cache_ctrl.m_timer_expired ^= 1; @@ -3216,10 +3621,8 @@ wl_iw_get_scan( else { g_ss_cache_ctrl.m_cons_br_scan_cnt++; } -#endif - +#endif - if (g_scan_specified_ssid) { list = kmalloc(len, GFP_KERNEL); @@ -3233,20 +3636,21 @@ wl_iw_get_scan( memset(list, 0, len); list->buflen = htod32(len); if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) { - WL_TRACE(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, len)); + WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error)); dwrq->length = len; - if (g_scan_specified_ssid) + if (g_scan_specified_ssid) { + g_scan_specified_ssid = 0; kfree(list); + } return 0; } list->buflen = dtoh32(list->buflen); list->version = dtoh32(list->version); list->count = dtoh32(list->count); - if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ - __FUNCTION__, list->version)); + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __FUNCTION__, list->version)); if (g_scan_specified_ssid) { g_scan_specified_ssid = 0; kfree(list); @@ -3254,16 +3658,14 @@ wl_iw_get_scan( return -EINVAL; } -#if !defined(CSCAN) +#if !defined(CSCAN) if (g_scan_specified_ssid) { wl_iw_add_bss_to_ss_cache(list); kfree(list); } -#endif -#if !defined(CSCAN) - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); #if defined(WL_IW_USE_ISCAN) if (g_scan_specified_ssid) WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count)); @@ -3275,27 +3677,25 @@ wl_iw_get_scan( counter += list_merge->count; if (list_merge->count > 0) len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, - extra+len_ret, buflen_from_user -len_ret); + extra+len_ret, buflen_from_user -len_ret); p_buf = p_buf->next; } WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter)); #else list_merge = (wl_scan_results_t *) g_scan; len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user); -#endif - MUTEX_UNLOCK_WL_SCAN_SET(); +#endif + mutex_unlock(&wl_cache_lock); if (g_ss_cache_ctrl.m_link_down) { - wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); } - + wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len); len_ret += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); -#else +#else - if (g_scan_specified_ssid) { WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count)); len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); @@ -3318,13 +3718,13 @@ wl_iw_get_scan( if (list_merge->count > 0) len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret, buflen_from_user -len_ret); -#endif +#endif } else { list = (wl_scan_results_t *) g_scan; len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); } -#endif +#endif #if defined(WL_IW_USE_ISCAN) @@ -3340,6 +3740,7 @@ wl_iw_get_scan( WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count)); return 0; } +#endif #if defined(WL_IW_USE_ISCAN) static int @@ -3359,6 +3760,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; @@ -3378,21 +3780,17 @@ 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); + WL_ERROR(("%ssysioc_pid\n", __FUNCTION__)); + return -EAGAIN; } - - #if !defined(CSCAN) if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); @@ -3403,18 +3801,17 @@ wl_iw_iscan_get_scan( } else { if (g_ss_cache_ctrl.m_link_down) { - wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); } if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) { g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; - + wl_iw_reset_ss_cache(); } g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid; g_ss_cache_ctrl.m_cons_br_scan_cnt++; } -#endif +#endif WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name)); apcnt = 0; @@ -3423,10 +3820,10 @@ wl_iw_iscan_get_scan( while (p_buf != iscan->list_cur) { list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; - counter += list->count; + counter += list->count; if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", __FUNCTION__, list->version)); return -EINVAL; } @@ -3434,26 +3831,27 @@ wl_iw_iscan_get_scan( bi = NULL; for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - WLC_IW_ISCAN_MAXLEN)); - + if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) || + (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) { + WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length))); + return -E2BIG; + } + if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end) return -E2BIG; - + iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); - iwe.u.data.length = dtoh32(bi->SSID_len); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (dtoh16(bi->capability) & DOT11_CAP_ESS) @@ -3463,25 +3861,22 @@ wl_iw_iscan_get_scan( event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); } - 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); - iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); iwe.u.qual.noise = 0x100 + bi->phy_noise; event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - wl_iw_handle_scanresults_ies(&event, end, info, bi); - iwe.cmd = SIOCGIWENCODE; if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; @@ -3490,7 +3885,6 @@ wl_iw_iscan_get_scan( iwe.u.data.length = 0; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - if (bi->rateset.count) { if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) return -E2BIG; @@ -3514,21 +3908,15 @@ wl_iw_iscan_get_scan( dwrq->flags = 0; #if !defined(CSCAN) - wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len); 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)); - - if (!dwrq->length) - return -EAGAIN; - return 0; } #endif @@ -3542,10 +3930,11 @@ wl_iw_set_essid( ) { int error; + wl_join_params_t join_params; + int join_params_size; WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); - memset(&g_ssid, 0, sizeof(g_ssid)); @@ -3563,11 +3952,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; } @@ -3595,7 +3997,6 @@ wl_iw_get_essid( ssid.SSID_len = dtoh32(ssid.SSID_len); - memcpy(extra, ssid.SSID, ssid.SSID_len); dwrq->length = ssid.SSID_len; @@ -3620,7 +4021,6 @@ wl_iw_set_nick( if (!extra) return -EINVAL; - if (dwrq->length > sizeof(iw->nickname)) return -E2BIG; @@ -4362,7 +4762,6 @@ wl_iw_set_pmksa( char eabuf[ETHER_ADDR_STR_LEN]; WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name)); - CHECK_EXTRA_FOR_NULL(extra); iwpmksa = (struct iw_pmksa *)extra; @@ -4379,8 +4778,7 @@ wl_iw_set_pmksa( uint j; pmkidptr = &pmkid; - bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, \ - ETHER_ADDR_LEN); + bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", @@ -4428,6 +4826,7 @@ wl_iw_set_pmksa( } else ret = -EINVAL; + { uint j; uint k; @@ -4440,7 +4839,7 @@ wl_iw_set_pmksa( WL_WSEC(("\n")); } } - WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid)); + WL_WSEC(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret)); for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { uint j; WL_WSEC(("PMKID[%d]: %s = ", i, @@ -4453,8 +4852,7 @@ wl_iw_set_pmksa( WL_WSEC(("\n")); if (!ret) - ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, \ - sizeof(pmkid_list)); + ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); return ret; } #endif @@ -4542,7 +4940,7 @@ wl_iw_set_wpaauth( if (iw->privacy_invoked && !val) { WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " - "we're a WPS enrollee\n", dev->name, __FUNCTION__)); + "we're a WPS enrollee\n", dev->name, __FUNCTION__)); if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); return error; @@ -4650,7 +5048,6 @@ wl_iw_set_wpaauth( return error; if (!(IW_WSEC_ENABLED(wsec))) { - if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); @@ -4665,7 +5062,7 @@ wl_iw_set_wpaauth( } break; } -#endif +#endif case IW_AUTH_WAPI_ENABLED: if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) return error; @@ -4793,13 +5190,12 @@ wl_iw_get_wpaauth( case IW_AUTH_PRIVACY_INVOKED: paramval = iw->privacy_invoked; break; - #endif } vwrq->value = paramval; return 0; } -#endif +#endif #ifdef SOFTAP @@ -4823,12 +5219,10 @@ wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) case 28: case 34: case 66: - if (!strnicmp(keystr, "0x", 2)) keystr += 2; else return -1; - case 10: case 26: case 32: @@ -4852,7 +5246,6 @@ wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) key->algo = CRYPTO_ALGO_WEP128; break; case 16: - key->algo = CRYPTO_ALGO_AES_CCM; break; case 32: @@ -4862,7 +5255,6 @@ wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) return -1; } - key->flags |= WL_PRIMARY_KEY; return 0; @@ -4870,14 +5262,14 @@ wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) #ifdef EXT_WPA_CRYPTO #define SHA1HashSize 20 -extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, \ - int iterations, u8 *buf, size_t buflen); +extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen); #else #define SHA1HashSize 20 -int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, \ - int iterations, u8 *buf, size_t buflen) +int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) { WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__)); return -1; @@ -4924,7 +5316,6 @@ int dev_iw_read_cfg1_bss_var(struct net_device *dev, int *val) } - #ifndef AP_ONLY static int wl_bssiovar_mkbuf( const char *iovar, @@ -4936,37 +5327,32 @@ static int wl_bssiovar_mkbuf( int *perr) { const char *prefix = "bsscfg:"; - int8* p; + int8 *p; uint prefixlen; uint namelen; uint iolen; - prefixlen = strlen(prefix); - namelen = strlen(iovar) + 1; + prefixlen = strlen(prefix); + namelen = strlen(iovar) + 1; iolen = prefixlen + namelen + sizeof(int) + paramlen; - if (buflen < 0 || iolen > (uint)buflen) { *perr = BCME_BUFTOOSHORT; return 0; } - p = (int8*)bufptr; + p = (int8 *)bufptr; - memcpy(p, prefix, prefixlen); p += prefixlen; - memcpy(p, iovar, namelen); p += namelen; - bssidx = htod32(bssidx); memcpy(p, &bssidx, sizeof(int32)); p += sizeof(int32); - if (paramlen) memcpy(p, param, paramlen); @@ -4976,8 +5362,6 @@ static int wl_bssiovar_mkbuf( #endif - - int get_user_params(char *user_params, struct iw_point *dwrq) { int ret = 0; @@ -4996,11 +5380,8 @@ int get_user_params(char *user_params, struct iw_point *dwrq) #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) - #if defined(CSCAN) - - static int wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan) { @@ -5010,16 +5391,22 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss int i; iscan_info_t *iscan = g_iscan; - WL_ERROR(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); + WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); 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) { i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16); i = ROUNDUP(i, sizeof(uint32)); @@ -5036,7 +5423,6 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16); } - iscan->iscan_ex_params_p->params.channel_num = \ htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \ (nchan & WL_SCAN_PARAMS_COUNT_MASK)); @@ -5045,7 +5431,6 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \ WL_SCAN_PARAMS_COUNT_MASK); - params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t)); iscan->iscan_ex_param_size = params_size; @@ -5090,7 +5475,7 @@ wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nss if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \ iscan->iscan_ex_param_size, \ iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { - WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); + WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); err = -1; } @@ -5140,7 +5525,6 @@ static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info str_ptr = extra; - if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) { WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__)); goto exit_proc; @@ -5187,11 +5571,9 @@ 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 { - WL_ERROR(("IWPRIV argument len = 0 \n")); return -1; } @@ -5244,15 +5626,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 @@ -5373,21 +5758,33 @@ wl_iw_set_cscan( goto exit_proc; } - + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { + + WL_ERROR(("%s Clean up First scan flag which is %d\n", \ + __FUNCTION__, g_first_broadcast_scan)); + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; + } + else { + WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", \ + __FUNCTION__, g_first_counter_scans)); + 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; } #endif - - #ifdef SOFTAP #ifndef AP_ONLY - static int thr_wait_for_2nd_eth_dev(void *data) { int ret = 0; @@ -5413,13 +5810,11 @@ static int thr_wait_for_2nd_eth_dev(void *data) ap_cfg_running = TRUE; - bcm_mdelay(500); + bcm_mdelay(500); - wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK"); fail: - WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); return ret; @@ -5498,7 +5893,7 @@ static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap fail : return res; -} +} static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) @@ -5518,13 +5913,14 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) int bsscfg_index = 1; char buf[WLC_IOCTL_SMLEN]; #endif - wl_iw_t *iw; if (!dev) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); return -1; } + net_os_wake_lock(dev); + WL_SOFTAP(("wl_iw: set ap profile:\n")); WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); WL_SOFTAP((" security = '%s'\n", ap->sec)); @@ -5533,11 +5929,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) WL_SOFTAP((" channel = %d\n", ap->channel)); WL_SOFTAP((" max scb = %d\n", ap->max_scb)); - iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK_SOFTAP_SET(iw->pub); - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_SOFTAP_SET, "SoftAP_SET"); - WAKE_LOCK(iw->pub, WAKE_LOCK_SOFTAP_SET); - #ifdef AP_ONLY if (ap_cfg_running) { wl_iw_softap_deassoc_stations(dev); @@ -5545,12 +5936,10 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } #endif - if (ap_cfg_running == FALSE) { #ifndef AP_ONLY - sema_init(&ap_eth_sema, 0); mpc = 0; @@ -5567,7 +5956,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } #ifdef AP_ONLY - apsta_var = 0; if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) { WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__)); @@ -5580,7 +5968,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var)); #else - apsta_var = 1; iolen = wl_bssiovar_mkbuf("apsta", bsscfg_index, &apsta_var, sizeof(apsta_var)+4, @@ -5591,7 +5978,7 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) goto fail; } WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); -#endif +#endif updown = 1; if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) { @@ -5620,7 +6007,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) ap->channel = 1; WL_ERROR(("%s auto channel failed, pick up channel=%d\n", \ __FUNCTION__, ap->channel)); - } channel = ap->channel; @@ -5646,7 +6032,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) ap_ssid.SSID_len = strlen(ap->ssid); strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); - #ifdef AP_ONLY if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", \ @@ -5656,7 +6041,6 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START"); ap_cfg_running = TRUE; #else - iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid), ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); ASSERT(iolen); @@ -5666,11 +6050,8 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) goto fail; } if (ap_cfg_running == FALSE) { - kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0); } else { - - if (ap_net_dev == NULL) { WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__)); goto fail; @@ -5679,13 +6060,11 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) WL_ERROR(("%s: %s Configure security & restart AP bss \n", \ __FUNCTION__, ap_net_dev->name)); - if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) { WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res)); goto fail; } - if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) { WL_ERROR(("%s fail to set bss up\n", __FUNCTION__)); goto fail; @@ -5693,15 +6072,12 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) } #endif fail: - WAKE_UNLOCK(iw->pub, WAKE_LOCK_SOFTAP_SET); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_SOFTAP_SET); - MUTEX_UNLOCK_SOFTAP_SET(iw->pub); - WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res)); + + net_os_wake_unlock(dev); + return res; } -#endif - static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) @@ -5726,10 +6102,7 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) WL_SOFTAP((" channel = %d\n", ap->channel)); WL_SOFTAP((" max scb = %d\n", ap->max_scb)); - if (strnicmp(ap->sec, "open", strlen("open")) == 0) { - - wsec = 0; res = dev_wlc_intvar_set(dev, "wsec", wsec); wpa_auth = WPA_AUTH_DISABLED; @@ -5741,7 +6114,6 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { - memset(&key, 0, sizeof(key)); wsec = WEP_ENABLED; @@ -5768,9 +6140,6 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) WL_SOFTAP(("=====================\n")); } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) { - - - wsec_pmk_t psk; size_t key_len; @@ -5784,18 +6153,15 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) return -1; } - if (key_len < WSEC_MAX_PSK_LEN) { unsigned char output[2*SHA1HashSize]; char key_str_buf[WSEC_MAX_PSK_LEN+1]; - memset(output, 0, sizeof(output)); pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); - + ptr = key_str_buf; for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) { - sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], \ (uint)output[i*4+1], (uint)output[i*4+2], \ (uint)output[i*4+3]); @@ -5817,7 +6183,6 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) { - wsec_pmk_t psk; size_t key_len; @@ -5831,25 +6196,24 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) return -1; } - if (key_len < WSEC_MAX_PSK_LEN) { unsigned char output[2*SHA1HashSize]; char key_str_buf[WSEC_MAX_PSK_LEN+1]; WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__)); - + pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32); - + ptr = key_str_buf; for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) { - WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int*)&output[i*4]))); - - sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], \ - (uint)output[i*4+1], (uint)output[i*4+2], \ - (uint)output[i*4+3]); + WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int *)&output[i*4]))); + + sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], + (uint)output[i*4+1], (uint)output[i*4+2], + (uint)output[i*4+3]); ptr += 8; } - printk("%s: passphase = %s\n", __FUNCTION__, key_str_buf); + WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf)); psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN); memcpy(psk.key, key_str_buf, psk.key_len); @@ -5894,22 +6258,21 @@ int get_parmeter_from_string( if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) { - strsep(str_ptr, "=,"); + strsep(str_ptr, "=,"); param_str_begin = *str_ptr; - strsep(str_ptr, "=,"); + strsep(str_ptr, "=,"); if (*str_ptr == NULL) { - parm_str_len = strlen(param_str_begin); } else { - param_str_end = *str_ptr-1; + param_str_end = *str_ptr-1; parm_str_len = param_str_end - param_str_begin; } WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len)); if (parm_str_len > param_max_len) { - WL_ERROR((" WARNING: extracted param len:%d is > MAX:%d\n", + WL_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n", parm_str_len, param_max_len)); parm_str_len = param_max_len; @@ -5917,35 +6280,33 @@ int get_parmeter_from_string( switch (param_type) { - case PTYPE_INTDEC: { - - int *pdst_int = dst; - char *eptr; - if (parm_str_len > sizeof(int_str)) - parm_str_len = sizeof(int_str); + case PTYPE_INTDEC: { + int *pdst_int = dst; + char *eptr; + + if (parm_str_len > sizeof(int_str)) + parm_str_len = sizeof(int_str); - memcpy(int_str, param_str_begin, parm_str_len); + memcpy(int_str, param_str_begin, parm_str_len); - *pdst_int = simple_strtoul(int_str, &eptr, 10); + *pdst_int = simple_strtoul(int_str, &eptr, 10); - WL_TRACE((" written as integer:%d\n", *pdst_int)); + WL_TRACE((" written as integer:%d\n", *pdst_int)); } break; - case PTYPE_STR_HEX: { - u8 *buf = dst; - - param_max_len = param_max_len >> 1; - hstr_2_buf(param_str_begin, buf, param_max_len); - print_buf(buf, param_max_len, 0); + case PTYPE_STR_HEX: { + u8 *buf = dst; + + param_max_len = param_max_len >> 1; + hstr_2_buf(param_str_begin, buf, param_max_len); + print_buf(buf, param_max_len, 0); } break; - default: - - memcpy(dst, param_str_begin, parm_str_len); - *((char *)dst + parm_str_len) = 0; - WL_ERROR((" written as a string:%s\n", (char *)dst)); + default: + memcpy(dst, param_str_begin, parm_str_len); + *((char *)dst + parm_str_len) = 0; + WL_TRACE((" written as a string:%s\n", (char *)dst)); break; - } return 0; @@ -5953,7 +6314,7 @@ int get_parmeter_from_string( WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n", __FUNCTION__, token, orig_str)); - return -1; + return -1; } } @@ -5962,33 +6323,32 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev) { int i; int res = 0; - char mac_buf[128] = {0}; - struct maclist *assoc_maclist = (struct maclist *) mac_buf; + struct maclist *assoc_maclist = (struct maclist *)mac_buf; memset(assoc_maclist, 0, sizeof(mac_buf)); - assoc_maclist->count = 8; + assoc_maclist->count = 8; res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128); if (res != 0) { - WL_SOFTAP((" Error:%d in :%s, Couldn't get ASSOC List\n", res, __FUNCTION__)); return res; } - if (assoc_maclist->count) - for (i = 0; i < assoc_maclist->count; i++) { + if (assoc_maclist->count) { + for (i = 0; i < assoc_maclist->count; i++) { scb_val_t scbval; + scbval.val = htod32(1); - bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN); WL_SOFTAP(("deauth STA:%d \n", i)); res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, - &scbval, sizeof(scb_val_t)); - - } else WL_SOFTAP((" STA ASSOC list is empty\n")); - + &scbval, sizeof(scb_val_t)); + } + } else { + WL_SOFTAP((" STA ASSOC list is empty\n")); + } if (res != 0) WL_SOFTAP((" Error:%d in :%s\n", res, __FUNCTION__)); @@ -6000,28 +6360,23 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev) } - static int iwpriv_softap_stop(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *ext) { int res = 0; - wl_iw_t *iw; - WL_SOFTAP(("got iwpriv AP_BSS_STOP \n")); + WL_SOFTAP(("got iwpriv AP_BSS_STOP\n")); if ((!dev) && (!ap_net_dev)) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); return res; } - iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK_SOFTAP_SET(iw->pub); - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_SOFTAP_STOP, "SoftAP_STOP"); - WAKE_LOCK(iw->pub, WAKE_LOCK_SOFTAP_STOP); + net_os_wake_lock(dev); - if ((ap_cfg_running == TRUE)) { + if ((ap_cfg_running == TRUE)) { #ifdef AP_ONLY wl_iw_softap_deassoc_stations(dev); #else @@ -6031,7 +6386,6 @@ static int iwpriv_softap_stop(struct net_device *dev, WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res)); #endif - bcm_mdelay(100); wrqu->data.length = 0; @@ -6040,25 +6394,22 @@ static int iwpriv_softap_stop(struct net_device *dev, else WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__)); - WAKE_UNLOCK(iw->pub, WAKE_LOCK_SOFTAP_STOP); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_SOFTAP_STOP); - MUTEX_UNLOCK_SOFTAP_SET(iw->pub); - WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res)); + + net_os_wake_unlock(dev); + return res; } - static int iwpriv_fw_reload(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *ext) + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) { - int ret = -1; char extra[256]; - char *fwstr = fw_path ; + char *fwstr = fw_path; WL_SOFTAP(("current firmware_path[]=%s\n", fwstr)); @@ -6068,7 +6419,6 @@ static int iwpriv_fw_reload(struct net_device *dev, info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr))); - if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) { char *str_ptr; @@ -6078,7 +6428,6 @@ static int iwpriv_fw_reload(struct net_device *dev, goto exit_proc; } - extra[wrqu->data.length] = 8; str_ptr = extra; @@ -6087,9 +6436,9 @@ static int iwpriv_fw_reload(struct net_device *dev, goto exit_proc; } - if (strstr(fwstr, "apsta") != NULL) { - WL_SOFTAP(("GOT APSTA FIRMWARE\n")); - ap_fw_loaded = TRUE; + if (strstr(fwstr, "apsta") != NULL) { + WL_SOFTAP(("GOT APSTA FIRMWARE\n")); + ap_fw_loaded = TRUE; } else { WL_SOFTAP(("GOT STA FIRMWARE\n")); ap_fw_loaded = FALSE; @@ -6104,12 +6453,13 @@ static int iwpriv_fw_reload(struct net_device *dev, exit_proc: return ret; } -#ifdef SOFTAP +#endif +#ifdef SOFTAP static int iwpriv_wpasupp_loop_tst(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *ext) + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) { int res = 0; char *params = NULL; @@ -6124,7 +6474,6 @@ static int iwpriv_wpasupp_loop_tst(struct net_device *dev, if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL))) return -ENOMEM; - if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) { kfree(params); return -EFAULT; @@ -6137,64 +6486,54 @@ static int iwpriv_wpasupp_loop_tst(struct net_device *dev, return -EFAULT; } - res = wl_iw_send_priv_event(dev, params); kfree(params); return res; } -#endif +#endif static int - iwpriv_en_ap_bss( +iwpriv_en_ap_bss( struct net_device *dev, struct iw_request_info *info, void *wrqu, char *extra) { int res = 0; - wl_iw_t *iw; if (!dev) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); return -1; } - WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); + net_os_wake_lock(dev); - iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK_SOFTAP_SET(iw->pub); - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_SOFTAP_START, "SoftAP_START"); - WAKE_LOCK(iw->pub, WAKE_LOCK_SOFTAP_START); + WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); - #ifndef AP_ONLY if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res)); } else { - if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res)); else - bcm_mdelay(100); } #endif - WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res)); - WAKE_UNLOCK(iw->pub, WAKE_LOCK_SOFTAP_START); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_SOFTAP_START); - MUTEX_UNLOCK_SOFTAP_SET(iw->pub); + + net_os_wake_unlock(dev); + return res; } static int get_assoc_sta_list(struct net_device *dev, char *buf, int len) { - WL_TRACE(("calling dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n", dev, WLC_GET_ASSOCLIST, buf, len)); @@ -6216,10 +6555,9 @@ set_ap_mac_list(struct net_device *dev, char *buf) ap_macmode = mac_mode; if (mac_mode == MACLIST_MODE_DISABLED) { - + bzero(&ap_black_list, sizeof(struct mflist)); - dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); } else { scb_val_t scbval; @@ -6227,38 +6565,35 @@ set_ap_mac_list(struct net_device *dev, char *buf) struct maclist *assoc_maclist = (struct maclist *) mac_buf; mac_mode = MACLIST_MODE_ALLOW; - + dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); - length = sizeof(white_maclist->count)+white_maclist->count*ETHER_ADDR_LEN; dev_wlc_ioctl(dev, WLC_SET_MACLIST, white_maclist, length); WL_SOFTAP(("White List, length %d:\n", length)); for (i = 0; i < white_maclist->count; i++) WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", - i, white_maclist->ea[i].octet[0], white_maclist->ea[i].octet[1], \ - white_maclist->ea[i].octet[2], \ - white_maclist->ea[i].octet[3], white_maclist->ea[i].octet[4], \ + i, white_maclist->ea[i].octet[0], white_maclist->ea[i].octet[1], + white_maclist->ea[i].octet[2], + white_maclist->ea[i].octet[3], white_maclist->ea[i].octet[4], white_maclist->ea[i].octet[5])); - bcopy(black_maclist, &ap_black_list, sizeof(ap_black_list)); WL_SOFTAP(("Black List, size %d:\n", sizeof(ap_black_list))); for (i = 0; i < ap_black_list.count; i++) WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", - i, ap_black_list.ea[i].octet[0], ap_black_list.ea[i].octet[1], \ - ap_black_list.ea[i].octet[2], \ - ap_black_list.ea[i].octet[3], \ + i, ap_black_list.ea[i].octet[0], ap_black_list.ea[i].octet[1], + ap_black_list.ea[i].octet[2], + ap_black_list.ea[i].octet[3], ap_black_list.ea[i].octet[4], ap_black_list.ea[i].octet[5])); - dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); if (assoc_maclist->count) { int j; for (i = 0; i < assoc_maclist->count; i++) { for (j = 0; j < white_maclist->count; j++) { - if (!bcmp(&assoc_maclist->ea[i], &white_maclist->ea[j], \ + if (!bcmp(&assoc_maclist->ea[i], &white_maclist->ea[j], ETHER_ADDR_LEN)) { WL_SOFTAP(("match allow, let it be\n")); break; @@ -6267,9 +6602,9 @@ set_ap_mac_list(struct net_device *dev, char *buf) if (j == white_maclist->count) { WL_SOFTAP(("match black, deauth it\n")); scbval.val = htod32(1); - bcopy(&assoc_maclist->ea[i], &scbval.ea, \ - ETHER_ADDR_LEN); - dev_wlc_ioctl(dev, \ + bcopy(&assoc_maclist->ea[i], &scbval.ea, + ETHER_ADDR_LEN); + dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scb_val_t)); } @@ -6278,7 +6613,7 @@ set_ap_mac_list(struct net_device *dev, char *buf) } return 0; } -#endif +#endif #ifdef SOFTAP @@ -6308,10 +6643,10 @@ int wl_iw_process_private_ascii_cmd( WL_SOFTAP((" AP_CFG \n")); - + if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) { - WL_ERROR(("ERROR: SoftAP CFG prams !\n")); - ret = -1; + WL_ERROR(("ERROR: SoftAP CFG prams !\n")); + ret = -1; } else { ret = set_ap_cfg(dev, &my_ap); } @@ -6320,14 +6655,12 @@ int wl_iw_process_private_ascii_cmd( WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n")); - WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name)); #ifndef AP_ONLY if (ap_net_dev == NULL) { - printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n"); + printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n"); } else { - if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0) WL_ERROR(("%s line %d fail to set bss up\n", \ __FUNCTION__, __LINE__)); @@ -6338,11 +6671,8 @@ int wl_iw_process_private_ascii_cmd( __FUNCTION__, __LINE__)); #endif } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) { - - - + /* no code yet */ } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) { - WL_SOFTAP((" \n temp DOWN SOFTAP\n")); #ifndef AP_ONLY if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { @@ -6353,9 +6683,9 @@ int wl_iw_process_private_ascii_cmd( } return ret; - } -#endif +#endif + static int wl_iw_set_priv( struct net_device *dev, struct iw_request_info *info, @@ -6366,7 +6696,6 @@ static int wl_iw_set_priv( int ret = 0; char * extra; - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); if (!(extra = kmalloc(dwrq->length, GFP_KERNEL))) return -ENOMEM; @@ -6375,96 +6704,103 @@ static int wl_iw_set_priv( return -EFAULT; } - WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d\n", + WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d", dev->name, extra, info->cmd, info->flags, dwrq->length)); + net_os_wake_lock(dev); if (dwrq->length && extra) { - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_PRIV, "wl_iw_set_priv"); - WAKE_LOCK(iw->pub, WAKE_LOCK_PRIV); + if (strnicmp(extra, "START", strlen("START")) == 0) { + wl_iw_control_wl_on(dev, info); + WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); + } if (g_onoff == G_WLAN_SET_OFF) { - if (strnicmp(extra, "START", strlen("START")) != 0) { - WL_ERROR(("%s First IOCTL after stop is NOT START \n", \ - __FUNCTION__)); - WAKE_UNLOCK(iw->pub, WAKE_LOCK_PRIV); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_PRIV); - kfree(extra); - return -EFAULT; - } else { - wl_iw_control_wl_on(dev, info); - WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); - } + WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__)); + kfree(extra); + net_os_wake_unlock(dev); + return -EFAULT; } - if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { + if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS WL_TRACE(("%s: active scan setting suppressed\n", dev->name)); #else ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra); -#endif - } - else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) +#endif + } else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS WL_TRACE(("%s: passive scan setting suppressed\n", dev->name)); #else ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra); -#endif - else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0) +#endif + else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0) ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0) + else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0) ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) + else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0) + else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0) ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) + else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) ret = wl_iw_control_wl_off(dev, info); else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) 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); #endif #ifdef CUSTOMER_HW2 - else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) + else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) + else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); #else - else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) + else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); #endif + else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0) + ret = wl_iw_get_power_mode(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); - } - else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) { + else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) { + wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra); + } else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) { WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n")); set_ap_mac_list(dev, (extra + PROFILE_OFFSET)); - } -#endif - else { - WL_TRACE(("Unkown PRIVATE command %s\n", extra)); + } +#endif + else { + WL_TRACE(("Unknown PRIVATE command: %s: ignored\n", extra)); snprintf(extra, MAX_WX_STRING, "OK"); dwrq->length = strlen("OK") + 1; - WL_ERROR(("Unkown PRIVATE command, ignored\n")); } - WAKE_UNLOCK(iw->pub, WAKE_LOCK_PRIV); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_PRIV); } + net_os_wake_unlock(dev); + if (extra) { - if (copy_to_user(dwrq->pointer, extra, dwrq->length)) { + if (copy_to_user(dwrq->pointer, extra, dwrq->length)) { kfree(extra); return -EFAULT; - } + } - kfree(extra); + kfree(extra); } return ret; @@ -6480,12 +6816,12 @@ static const iw_handler wl_iw_handler[] = (iw_handler) wl_iw_get_freq, (iw_handler) wl_iw_set_mode, (iw_handler) wl_iw_get_mode, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) NULL, - (iw_handler) wl_iw_get_range, - (iw_handler) wl_iw_set_priv, - (iw_handler) NULL, + (iw_handler) NULL, + (iw_handler) wl_iw_get_wext_rssi, + (iw_handler) NULL, + (iw_handler) wl_iw_get_range, + (iw_handler) wl_iw_set_priv, + (iw_handler) NULL, (iw_handler) NULL, (iw_handler) NULL, (iw_handler) wl_iw_set_spy, @@ -6518,7 +6854,7 @@ static const iw_handler wl_iw_handler[] = #endif (iw_handler) wl_iw_set_essid, (iw_handler) wl_iw_get_essid, - (iw_handler) wl_iw_set_nick, + (iw_handler) wl_iw_set_nick, (iw_handler) wl_iw_get_nick, (iw_handler) NULL, (iw_handler) NULL, @@ -6569,45 +6905,37 @@ static const iw_handler wl_iw_priv_handler[] = { (iw_handler)wl_iw_control_wl_off, NULL, (iw_handler)wl_iw_control_wl_on, -#ifdef SOFTAP - - +#ifdef SOFTAP NULL, (iw_handler)iwpriv_set_ap_config, - - NULL, (iw_handler)iwpriv_get_assoc_list, - NULL, (iw_handler)iwpriv_set_mac_filters, - NULL, (iw_handler)iwpriv_en_ap_bss, - NULL, (iw_handler)iwpriv_wpasupp_loop_tst, - + NULL, (iw_handler)iwpriv_softap_stop, - + NULL, (iw_handler)iwpriv_fw_reload, -#endif +#endif #if defined(CSCAN) - + NULL, (iw_handler)iwpriv_set_cscan #endif }; -static const struct iw_priv_args wl_iw_priv_args[] = -{ - { +static const struct iw_priv_args wl_iw_priv_args[] = { + { WL_IW_SET_ACTIVE_SCAN, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, @@ -6651,30 +6979,28 @@ static const struct iw_priv_args wl_iw_priv_args[] = }, #ifdef SOFTAP - - { WL_SET_AP_CFG, - IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, 0, "AP_SET_CFG" }, { WL_AP_STA_LIST, - 0, - IW_PRIV_TYPE_CHAR | 0, + 0, + IW_PRIV_TYPE_CHAR | 0, "AP_GET_STA_LIST" }, { WL_AP_MAC_FLTR, - IW_PRIV_TYPE_CHAR | 256, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, "AP_SET_MAC_FLTR" }, - { + { WL_AP_BSS_START, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, @@ -6683,33 +7009,34 @@ static const struct iw_priv_args wl_iw_priv_args[] = { AP_LPB_CMD, - IW_PRIV_TYPE_CHAR | 256, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, "AP_LPB_CMD" }, - { + { WL_AP_STOP, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, "AP_BSS_STOP" }, - { + + { WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, "WL_FW_RELOAD" }, -#endif +#endif #if defined(CSCAN) - { + { WL_COMBO_SCAN, - IW_PRIV_TYPE_CHAR | 1024, + IW_PRIV_TYPE_CHAR | 1024, 0, "CSCAN" }, -#endif - }; +#endif +}; const struct iw_handler_def wl_iw_handler_def = { @@ -6723,11 +7050,10 @@ const struct iw_handler_def wl_iw_handler_def = #if WIRELESS_EXT >= 19 get_wireless_stats: dhd_get_wireless_stats, #endif - }; +}; #endif - int wl_iw_ioctl( struct net_device *dev, struct ifreq *rq, @@ -6740,11 +7066,14 @@ int wl_iw_ioctl( char *extra = NULL; int token_size = 1, max_tokens = 0, ret = 0; - WL_TRACE(("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd)); + net_os_wake_lock(dev); + + WL_TRACE(("%s: cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd)); if (cmd < SIOCIWFIRST || IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) { WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd)); + net_os_wake_unlock(dev); return -EOPNOTSUPP; } @@ -6767,7 +7096,6 @@ int wl_iw_ioctl( break; case SIOCGIWRANGE: - max_tokens = sizeof(struct iw_range) + 500; break; @@ -6810,14 +7138,18 @@ int wl_iw_ioctl( if (wrq->u.data.length > max_tokens) { WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n", \ __FUNCTION__, cmd, wrq->u.data.length, max_tokens)); - return -E2BIG; + ret = -E2BIG; + goto wl_iw_ioctl_done; + } + if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) { + ret = -ENOMEM; + goto wl_iw_ioctl_done; } - if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) - return -ENOMEM; if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { kfree(extra); - return -EFAULT; + ret = -EFAULT; + goto wl_iw_ioctl_done; } } @@ -6829,12 +7161,17 @@ int wl_iw_ioctl( if (extra) { if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { kfree(extra); - return -EFAULT; + ret = -EFAULT; + goto wl_iw_ioctl_done; } kfree(extra); } +wl_iw_ioctl_done: + + net_os_wake_unlock(dev); + return ret; } @@ -6933,11 +7270,11 @@ wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) else return FALSE; } -#endif +#endif #ifndef IW_CUSTOM_MAX #define IW_CUSTOM_MAX 256 -#endif +#endif void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) @@ -6950,23 +7287,22 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) uint16 flags = ntoh16(e->flags); uint32 datalen = ntoh32(e->datalen); uint32 status = ntoh32(e->status); - wl_iw_t *iw; uint32 toto; + static uint32 roam_no_success = 0; + static bool roam_no_success_send = FALSE; memset(&wrqu, 0, sizeof(wrqu)); memset(extra, 0, sizeof(extra)); - iw = 0; if (!dev) { WL_ERROR(("%s: dev is null\n", __FUNCTION__)); return; } - iw = *(wl_iw_t **)netdev_priv(dev); + net_os_wake_lock(dev); WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type)); - switch (event_type) { #if defined(SOFTAP) case WLC_E_PRUNE: @@ -6976,9 +7312,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) macaddr[0], macaddr[1], macaddr[2], macaddr[3], \ macaddr[4], macaddr[5])); - - if (ap_macmode) - { + if (ap_macmode) { int i; for (i = 0; i < ap_black_list.count; i++) { if (!bcmp(macaddr, &ap_black_list.ea[i], \ @@ -6989,7 +7323,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } if (i == ap_black_list.count) { - char mac_buf[32] = {0}; sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X", macaddr[0], macaddr[1], macaddr[2], @@ -6999,7 +7332,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } } break; -#endif +#endif case WLC_E_TXFAIL: cmd = IWEVTXDROP; memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); @@ -7013,22 +7346,43 @@ 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"); - return; + goto wl_iw_event_end; } -#endif +#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) { + roam_no_success++; + if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) { + + roam_no_success_send = TRUE; + bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); + bzero(&extra, ETHER_ADDR_LEN); + cmd = SIOCGIWAP; + WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", \ + __FUNCTION__)); + } else { + WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success)); + goto wl_iw_event_end; + } + } else { + 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"); - return; + goto wl_iw_event_end; } -#endif +#endif cmd = SIOCGIWAP; bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; @@ -7038,54 +7392,50 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) case WLC_E_NDIS_LINK: cmd = SIOCGIWAP; if (!(flags & WLC_EVENT_MSG_LINK)) { - - #ifdef SOFTAP #ifdef AP_ONLY if (ap_cfg_running) { #else if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { #endif - - WL_SOFTAP(("AP DOWN %d\n", event_type)); - wl_iw_send_priv_event(priv_dev, "AP_DOWN"); - } else { - WL_TRACE(("STA_Link Down\n")); + WL_SOFTAP(("AP DOWN %d\n", event_type)); + wl_iw_send_priv_event(priv_dev, "AP_DOWN"); + } else { + WL_TRACE(("STA_Link Down\n")); + g_ss_cache_ctrl.m_link_down = 1; + } +#else g_ss_cache_ctrl.m_link_down = 1; - } -#else - g_ss_cache_ctrl.m_link_down = 1; -#endif +#endif WL_TRACE(("Link Down\n")); bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); bzero(&extra, ETHER_ADDR_LEN); - WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_LINK_DOWN_TMOUT, 20 * HZ); } else { - memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); g_ss_cache_ctrl.m_link_down = 0; - + memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN); -#ifdef SOFTAP +#ifdef SOFTAP #ifdef AP_ONLY if (ap_cfg_running) { #else if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { #endif - WL_SOFTAP(("AP UP %d\n", event_type)); wl_iw_send_priv_event(priv_dev, "AP_UP"); } else { WL_TRACE(("STA_LINK_UP\n")); + roam_no_success_send = FALSE; + roam_no_success = 0; } -#else -#endif +#endif WL_TRACE(("Link UP\n")); } + net_os_wake_lock_timeout_enable(dev); wrqu.addr.sa_family = ARPHRD_ETHER; break; case WLC_E_ACTION_FRAME: @@ -7152,7 +7502,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) count--; } } - return; + goto wl_iw_event_end; } #endif #endif @@ -7173,7 +7523,21 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) cmd = SIOCGIWSCAN; wrqu.data.length = strlen(extra); WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); -#endif +#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: @@ -7182,12 +7546,14 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; } #ifndef SANDGATE2G - if (cmd) { - if (cmd == SIOCGIWSCAN) - wireless_send_event(dev, cmd, &wrqu, NULL); - else - wireless_send_event(dev, cmd, &wrqu, extra); - } + if (cmd) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) + if (cmd == SIOCGIWSCAN) + wireless_send_event(dev, cmd, &wrqu, NULL); + else +#endif + wireless_send_event(dev, cmd, &wrqu, extra); + } #endif #if WIRELESS_EXT > 14 @@ -7200,9 +7566,10 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) wireless_send_event(dev, cmd, &wrqu, extra); #endif } -#endif - -#endif +#endif +wl_iw_event_end: + net_os_wake_unlock(dev); +#endif } int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) @@ -7301,13 +7668,11 @@ wl_iw_bt_flag_set( #endif if (set == TRUE) { - - dev_wlc_bufvar_set(dev, "btc_flags", \ + dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on)); } else { - - dev_wlc_bufvar_set(dev, "btc_flags", \ + dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); } @@ -7322,7 +7687,7 @@ wl_iw_bt_timerfunc(ulong data) bt_info_t *bt_local = (bt_info_t *)data; bt_local->timer_on = 0; WL_TRACE(("%s\n", __FUNCTION__)); - + up(&bt_local->bt_sem); } @@ -7332,21 +7697,22 @@ _bt_dhcp_sysioc_thread(void *data) DAEMONIZE("dhcp_sysioc"); while (down_interruptible(&g_bt->bt_sem) == 0) { + + net_os_wake_lock(g_bt->dev); + if (g_bt->timer_on) { - del_timer(&g_bt->timer); g_bt->timer_on = 0; + del_timer_sync(&g_bt->timer); } switch (g_bt->bt_state) { case BT_DHCP_START: - g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW; - mod_timer(&g_bt->timer, jiffies + \ - BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000); + mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000); g_bt->timer_on = 1; break; + case BT_DHCP_OPPORTUNITY_WINDOW: - WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \ __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM)); if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE); @@ -7354,8 +7720,8 @@ _bt_dhcp_sysioc_thread(void *data) mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); g_bt->timer_on = 1; break; + case BT_DHCP_FLAG_FORCE_TIMEOUT: - WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \ __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME)); @@ -7363,6 +7729,7 @@ _bt_dhcp_sysioc_thread(void *data) g_bt->bt_state = BT_DHCP_IDLE; g_bt->timer_on = 0; break; + default: WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \ g_bt->bt_state)); @@ -7370,13 +7737,16 @@ _bt_dhcp_sysioc_thread(void *data) g_bt->bt_state = BT_DHCP_IDLE; g_bt->timer_on = 0; break; - } + } + + net_os_wake_unlock(g_bt->dev); } if (g_bt->timer_on) { - del_timer(&g_bt->timer); g_bt->timer_on = 0; + del_timer_sync(&g_bt->timer); } + complete_and_exit(&g_bt->bt_exited, 0); } @@ -7429,17 +7799,22 @@ wl_iw_bt_init(struct net_device *dev) return 0; } -int wl_iw_attach(struct net_device *dev, void * dhdp) +int wl_iw_attach(struct net_device *dev, void *dhdp) { int params_size; wl_iw_t *iw; #if defined(WL_IW_USE_ISCAN) iscan_info_t *iscan = NULL; +#endif + + mutex_init(&wl_cache_lock); +#if defined(WL_IW_USE_ISCAN) 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); @@ -7447,11 +7822,9 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); #endif iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); - if (!iscan) return -ENOMEM; memset(iscan, 0, sizeof(iscan_info_t)); - iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); if (!iscan->iscan_ex_params_p) @@ -7462,12 +7835,11 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) g_iscan = iscan; iscan->dev = dev; iscan->iscan_state = ISCAN_STATE_IDLE; - g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; + g_first_counter_scans = 0; 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; @@ -7477,19 +7849,15 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); if (iscan->sysioc_pid < 0) return -ENOMEM; -#endif +#endif iw = *(wl_iw_t **)netdev_priv(dev); iw->pub = (dhd_pub_t *)dhdp; - MUTEX_LOCK_INIT(iw->pub); - MUTEX_LOCK_WL_SCAN_SET_INIT(); #ifdef SOFTAP priv_dev = dev; - MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub); #endif g_scan = NULL; - g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL); if (!g_scan) return -ENOMEM; @@ -7498,12 +7866,10 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) g_scan_specified_ssid = 0; #if !defined(CSCAN) - wl_iw_init_ss_cache_ctrl(); -#endif - - wl_iw_bt_init(dev); +#endif + wl_iw_bt_init(dev); return 0; } @@ -7520,17 +7886,17 @@ void wl_iw_detach(void) KILL_PROC(iscan->sysioc_pid, SIGTERM); wait_for_completion(&iscan->sysioc_exited); } - MUTEX_LOCK_WL_SCAN_SET(); + mutex_lock(&wl_cache_lock); while (iscan->list_hdr) { buf = iscan->list_hdr->next; kfree(iscan->list_hdr); iscan->list_hdr = buf; } - MUTEX_UNLOCK_WL_SCAN_SET(); kfree(iscan->iscan_ex_params_p); kfree(iscan); g_iscan = NULL; -#endif + mutex_unlock(&wl_cache_lock); +#endif if (g_scan) kfree(g_scan); @@ -7538,13 +7904,11 @@ void wl_iw_detach(void) g_scan = NULL; #if !defined(CSCAN) wl_iw_release_ss_cache_ctrl(); -#endif +#endif wl_iw_bt_release(); - #ifdef SOFTAP if (ap_cfg_running) { WL_TRACE(("\n%s AP is going down\n", __FUNCTION__)); - wl_iw_send_priv_event(priv_dev, "AP_DOWN"); } #endif diff --git a/drivers/net/wireless/bcm4329/wl_iw.h b/drivers/net/wireless/bcm4329/wl_iw.h index 6375e94bae96..43088cf886bd 100644 --- a/drivers/net/wireless/bcm4329/wl_iw.h +++ b/drivers/net/wireless/bcm4329/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.36.4.1 2010/09/10 19:24:30 Exp $ */ @@ -43,29 +43,41 @@ #define GET_HOME_DWELL "HOME=" #define GET_SCAN_TYPE "TYPE=" -#define BAND_GET_CMD "BANDGET" -#define BAND_SET_CMD "BANDSET" - -#define SOFTAP 1 - - -#define WL_IW_RSSI_MINVAL -200 -#define WL_IW_RSSI_NO_SIGNAL -91 -#define WL_IW_RSSI_VERY_LOW -80 -#define WL_IW_RSSI_LOW -70 -#define WL_IW_RSSI_GOOD -68 -#define WL_IW_RSSI_VERY_GOOD -58 -#define WL_IW_RSSI_EXCELLENT -57 -#define WL_IW_RSSI_INVALID 0 -#define MAX_WX_STRING 80 -#define isprint(c) bcm_isprint(c) +#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 "SETSUSPENDOPT" +#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 +#define WL_IW_RSSI_VERY_LOW -80 +#define WL_IW_RSSI_LOW -70 +#define WL_IW_RSSI_GOOD -68 +#define WL_IW_RSSI_VERY_GOOD -58 +#define WL_IW_RSSI_EXCELLENT -57 +#define WL_IW_RSSI_INVALID 0 +#define MAX_WX_STRING 80 +#define isprint(c) bcm_isprint(c) #define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) -#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) +#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) #define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) #define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) #define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) -#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) -#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) +#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) +#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) #define WL_SET_AP_CFG (SIOCIWFIRSTPRIV+15) @@ -75,12 +87,12 @@ #define AP_LPB_CMD (SIOCIWFIRSTPRIV+23) #define WL_AP_STOP (SIOCIWFIRSTPRIV+25) #define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27) -#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29) +#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29) #define WL_AP_SPARE3 (SIOCIWFIRSTPRIV+31) -#define G_SCAN_RESULTS 8*1024 -#define WE_ADD_EVENT_FIX 0x80 -#define G_WLAN_SET_ON 0 -#define G_WLAN_SET_OFF 1 +#define G_SCAN_RESULTS (8*1024) +#define WE_ADD_EVENT_FIX 0x80 +#define G_WLAN_SET_ON 0 +#define G_WLAN_SET_OFF 1 #define CHECK_EXTRA_FOR_NULL(extra) \ if (!extra) { \ @@ -94,9 +106,9 @@ typedef struct wl_iw { struct iw_statistics wstats; int spy_num; - uint32 pwsec; - uint32 gwsec; - bool privacy_invoked; + uint32 pwsec; + uint32 gwsec; + bool privacy_invoked; struct ether_addr spy_addr[IW_MAX_SPY]; struct iw_quality spy_qual[IW_MAX_SPY]; @@ -104,19 +116,19 @@ typedef struct wl_iw { dhd_pub_t * pub; } wl_iw_t; -int wl_control_wl_start(struct net_device *dev); #define WLC_IW_SS_CACHE_MAXLEN 512 #define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32 #define WLC_IW_BSS_INFO_MAXLEN \ (WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN) typedef struct wl_iw_ss_cache { - struct wl_iw_ss_cache *next; uint32 buflen; uint32 version; uint32 count; - int dirty; wl_bss_info_t bss_info[1]; + char dummy[WLC_IW_BSS_INFO_MAXLEN - sizeof(wl_bss_info_t)]; + int dirty; + struct wl_iw_ss_cache *next; } wl_iw_ss_cache_t; typedef struct wl_iw_ss_cache_ctrl { @@ -143,36 +155,48 @@ struct ap_profile { uint8 ssid[SSID_LEN]; uint8 sec[SEC_LEN]; uint8 key[KEY_LEN]; - uint32 channel; + uint32 channel; uint32 preamble; - uint32 max_scb; + uint32 max_scb; }; #define MACLIST_MODE_DISABLED 0 #define MACLIST_MODE_ENABLED 1 -#define MACLIST_MODE_ALLOW 2 +#define MACLIST_MODE_ALLOW 2 struct mflist { uint count; struct ether_addr ea[16]; }; + struct mac_list_set { uint32 mode; struct mflist white_list; struct mflist black_list; }; -#endif +#endif #if WIRELESS_EXT > 12 #include extern const struct iw_handler_def wl_iw_handler_def; -#endif +#endif extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); int wl_iw_attach(struct net_device *dev, void * dhdp); void wl_iw_detach(void); +int wl_control_wl_start(struct net_device *dev); + +extern int net_os_wake_lock(struct net_device *dev); +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) \ @@ -190,6 +214,31 @@ void wl_iw_detach(void); 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, ushort 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, ushort 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 1 +#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 { @@ -203,13 +252,13 @@ typedef struct cscan_tlv { #define CSCAN_TLV_PREFIX 'S' #define CSCAN_TLV_VERSION 1 #define CSCAN_TLV_SUBVERSION 0 -#define CSCAN_TLV_TYPE_SSID_IE 'S' -#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' -#define CSCAN_TLV_TYPE_NPROBE_IE 'N' -#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' -#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' -#define CSCAN_TLV_TYPE_HOME_IE 'H' -#define CSCAN_TLV_TYPE_STYPE_IE 'T' +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' +#define CSCAN_TLV_TYPE_NPROBE_IE 'N' +#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' +#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' +#define CSCAN_TLV_TYPE_HOME_IE 'H' +#define CSCAN_TLV_TYPE_STYPE_IE 'T' extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \ int channel_num, int *bytes_left);