diff options
Diffstat (limited to 'bcm4329/src')
98 files changed, 5198 insertions, 945 deletions
diff --git a/bcm4329/src/Makerules b/bcm4329/src/Makerules index 511def2..06ee2fe 100644 --- a/bcm4329/src/Makerules +++ b/bcm4329/src/Makerules @@ -2,7 +2,7 @@ # Top level Makerules # it uses Makerules.env for build env vars and optional branding.inc # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/Makerules.env b/bcm4329/src/Makerules.env index 189f053..dbe4c39 100644 --- a/bcm4329/src/Makerules.env +++ b/bcm4329/src/Makerules.env @@ -59,7 +59,7 @@ endif export TARGETENV # TARGETOS defaults to HOSTOS in most cases -ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "linuxarm" "linuxarm_le" "android" "linuxmips" "sun4" "cygwin32" "win32" "macos"), ) +ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "linuxarm" "linuxarm_le" "android" "linuxarm_omap" "linuxmips" "sun4" "cygwin32" "win32" "macos"), ) TARGETOS = $(HOSTOS) endif ifeq ($(TARGETENV), bcmmips) @@ -91,6 +91,9 @@ ifndef TARGETARCH ifneq ($(findstring "$(TARGETENV)", "linuxarm" "nucleusarm"), ) TARGETARCH = arm endif + ifneq ($(findstring "$(TARGETENV)", "linuxarm_omap"), ) + TARGETARCH = arm_omap + endif ifneq ($(findstring "$(TARGETENV)", "bcmmips" "linuxmips"), ) TARGETARCH = mips endif diff --git a/bcm4329/src/bcmsdio/linux/Makefile b/bcm4329/src/bcmsdio/linux/Makefile index 9e265d4..41ed016 100644 --- a/bcm4329/src/bcmsdio/linux/Makefile +++ b/bcm4329/src/bcmsdio/linux/Makefile @@ -1,7 +1,7 @@ # GNU Makefile for Broadcom BCMSDH Lower-level Driver # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/bcmsdio/linux/makefile.26 b/bcm4329/src/bcmsdio/linux/makefile.26 index ffbde11..b1f13eb 100644 --- a/bcm4329/src/bcmsdio/linux/makefile.26 +++ b/bcm4329/src/bcmsdio/linux/makefile.26 @@ -2,7 +2,7 @@ # Makefile fragment for Linux 2.6 # Broadcom BCMSDH Driver # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/bcmsdio/sys/bcmpcispi.c b/bcm4329/src/bcmsdio/sys/bcmpcispi.c index ba3e0c5..c0a66f1 100644 --- a/bcm4329/src/bcmsdio/sys/bcmpcispi.c +++ b/bcm4329/src/bcmsdio/sys/bcmpcispi.c @@ -1,7 +1,7 @@ /* * Broadcom SPI over PCI-SPI Host Controller, low-level hardware driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh.c b/bcm4329/src/bcmsdio/sys/bcmsdh.c index c9906e2..bb3608d 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh.c @@ -2,7 +2,7 @@ * BCMSDH interface glue * implement bcmsdh API for SDIOH driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.c,v 1.35.2.1.4.8.6.11 2009/10/20 09:48:20 Exp $ + * $Id: bcmsdh.c,v 1.35.2.1.4.8.6.12 2009/11/04 20:36:52 Exp $ */ /* ****************** BCMSDH Interface Functions *************************** */ @@ -40,9 +40,6 @@ #include <sdio.h> /* sdio spec */ -/* Defines number of access retries to configuration registers */ -#define SDIOH_API_ACCESS_RETRY_LIMIT 2 - const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; @@ -59,7 +56,6 @@ struct bcmsdh_info bcmsdh_info_t * l_bcmsdh = NULL; #if defined(OOB_INTR_ONLY) && defined(HW_OOB) - extern int sdioh_enable_hw_oob_intr(void *sdioh, bool enable); @@ -68,7 +64,6 @@ bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) { sdioh_enable_hw_oob_intr(sdh->sdioh, enable); } - #endif bcmsdh_info_t * @@ -210,9 +205,6 @@ bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif uint8 data = 0; if (!bcmsdh) @@ -220,15 +212,7 @@ bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) ASSERT(bcmsdh->init_success); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif if (err) *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); @@ -243,24 +227,13 @@ bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; SDIOH_API_RC status; -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - int32 retry = 0; -#endif if (!bcmsdh) bcmsdh = l_bcmsdh; ASSERT(bcmsdh->init_success); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - do { - if (retry) /* wait for 1 ms till bus get settled down */ - OSL_DELAY(1000); -#endif status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -#ifdef SDIOH_API_ACCESS_RETRY_LIMIT - } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -#endif if (err) *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c index 8787904..79d610b 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c @@ -1,7 +1,7 @@ /* * SDIO access interface for drivers - linux specific (pci only) * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.8 2009/10/15 22:48:28 Exp $ + * $Id: bcmsdh_linux.c,v 1.42.10.10.2.12 2010/03/10 03:09:48 Exp $ */ /** @@ -75,7 +75,7 @@ struct bcmsdh_hc { bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ void *ch; unsigned int oob_irq; - unsigned long oob_flags; + unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ }; static bcmsdh_hc_t *sdhcinfo = NULL; @@ -176,7 +176,7 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ int irq = 0; uint32 vendevid; - unsigned long irq_flags = IRQF_TRIGGER_FALLING; + unsigned long irq_flags = 0; #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) pdev = to_platform_device(dev); @@ -187,6 +187,7 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ #if defined(OOB_INTR_ONLY) + irq_flags = IRQF_TRIGGER_FALLING; irq = dhd_customer_oob_irq_map(&irq_flags); if (irq < 0) { SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); @@ -334,6 +335,18 @@ static struct pci_driver bcmsdh_pci_driver = { }; +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 */ +module_param(sd_pci_slot, uint, 0); + + /** * Detect supported SDIO Host Controller and attach if found. * @@ -349,6 +362,26 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bcmsdh_info_t *sdh = NULL; int rc; + if (sd_pci_slot != 0xFFFFffff) { + 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)); + 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)); + } + if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) || (pdev->device == PCIXX21_FLASHMEDIA0_ID))) { uint32 config_reg; @@ -547,6 +580,8 @@ static irqreturn_t wlan_oob_irq(int irq, void *dev_id) return IRQ_HANDLED; } + WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); + dhdsdio_isr((void *)dhdp->bus); return IRQ_HANDLED; @@ -560,6 +595,7 @@ int bcmsdh_register_oob_intr(void * dhdp) dev_set_drvdata(sdhcinfo->dev, dhdp); + /* Refer to customer Host IRQ docs about proper irqflags definition */ error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags, "bcmsdh_sdmmc", NULL); diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c index d5da588..68b4b24 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.27 2009/10/28 19:42:29 Exp $ + * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.28 2009/11/04 20:36:52 Exp $ */ #include <typedefs.h> @@ -211,26 +211,30 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) } #if defined(OOB_INTR_ONLY) && defined(HW_OOB) -#define _SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */ extern SDIOH_API_RC -sdioh_enable_func_intr(uint32 func) +sdioh_enable_func_intr(void) { uint8 reg; int err; if (gInstance->func[0]) { sdio_claim_host(gInstance->func[0]); - reg = sdio_readb(gInstance->func[0], _SDIO_CCCR_IENx, &err); + + reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); if (err) { sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); sdio_release_host(gInstance->func[0]); return SDIOH_API_RC_FAIL; } - reg |= 1 << func; /* enable function-x interrupt */ - reg |= 1; /* Master interrupt enable */ - sdio_writeb(gInstance->func[0], reg, _SDIO_CCCR_IENx, &err); + + reg |= 1 << 1; /* enable function-1 interrupt */ + reg |= 2 << 1; /* enable function-2 interrupt */ + reg |= 1; /* Master interrupt enable */ + + sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); sdio_release_host(gInstance->func[0]); + if (err) { sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); return SDIOH_API_RC_FAIL; @@ -238,28 +242,30 @@ sdioh_enable_func_intr(uint32 func) } return SDIOH_API_RC_SUCCESS; - } extern SDIOH_API_RC -sdioh_disable_func_intr(uint32 func) +sdioh_disable_func_intr(void) { uint8 reg; int err; if (gInstance->func[0]) { sdio_claim_host(gInstance->func[0]); - reg = sdio_readb(gInstance->func[0], _SDIO_CCCR_IENx, &err); + reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); if (err) { sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); sdio_release_host(gInstance->func[0]); return SDIOH_API_RC_FAIL; } - reg &= ~(1 << func); + + reg &= ~(1 << 1); + reg &= ~(1 << 2); /* Disable master interrupt with the last function interrupt */ if (!(reg & 0xFE)) reg = 0; - sdio_writeb(gInstance->func[0], reg, _SDIO_CCCR_IENx, &err); + sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_release_host(gInstance->func[0]); if (err) { sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); @@ -267,7 +273,6 @@ sdioh_disable_func_intr(uint32 func) } } return SDIOH_API_RC_SUCCESS; - } #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ @@ -298,7 +303,7 @@ sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) sdio_release_host(gInstance->func[1]); } #elif defined(HW_OOB) - sdioh_enable_func_intr(2); + sdioh_enable_func_intr(); #endif /* defined(OOB_INTR_ONLY) */ return SDIOH_API_RC_SUCCESS; } @@ -328,7 +333,7 @@ sdioh_interrupt_deregister(sdioh_info_t *sd) sd->intr_handler = NULL; sd->intr_handler_arg = NULL; #elif defined(HW_OOB) - sdioh_disable_func_intr(2); + sdioh_disable_func_intr(); #endif /* !defined(OOB_INTR_ONLY) */ return SDIOH_API_RC_SUCCESS; } @@ -678,7 +683,6 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) } #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) { @@ -794,8 +798,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by * depending upon MMC driver change. * As of this time, this is temporaray one */ - sdio_f0_writeb(gInstance->func[func], *byte, - regaddr, &err_ret); + sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); sdio_release_host(gInstance->func[func]); } #endif /* MMC_SDIO_ABORT */ @@ -1066,13 +1069,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u extern int sdioh_abort(sdioh_info_t *sd, uint func) { - char t_func = (char) func; - 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, &t_func); + sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, (uint8 *)&func); #endif /* defined(MMC_SDIO_ABORT) */ sd_trace(("%s: Exit\n", __FUNCTION__)); @@ -1260,7 +1261,7 @@ sdioh_start(sdioh_info_t *si, int stage) sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) - sdioh_enable_func_intr(2); + sdioh_enable_func_intr(); #endif bcmsdh_oob_intr_set(TRUE); #endif /* !defined(OOB_INTR_ONLY) */ @@ -1289,7 +1290,7 @@ sdioh_stop(sdioh_info_t *si) sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) - sdioh_disable_func_intr(2); + sdioh_disable_func_intr(); #endif bcmsdh_oob_intr_set(FALSE); #endif /* !defined(OOB_INTR_ONLY) */ diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c index 3643d1c..871e8a9 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.10 2009/10/14 04:32:13 Exp $ + * $Id: bcmsdh_sdmmc_linux.c,v 1.1.2.5.6.11 2009/11/04 20:36:52 Exp $ */ #include <typedefs.h> @@ -51,7 +51,6 @@ #include <dhd_dbg.h> - extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); @@ -81,6 +80,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret = 0; + static struct sdio_func sdio_func_0; sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); @@ -88,8 +88,9 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, sd_trace(("Function#: 0x%04x\n", func->num)); if (func->num == 1) { - /* Keep a copy of F1's 'func' in F0, just in case... */ - gInstance->func[0] = func; + sdio_func_0.num = 0; + sdio_func_0.card = func->card; + gInstance->func[0] = &sdio_func_0; if(func->device == 0x4) { /* 4318 */ gInstance->func[2] = NULL; sd_trace(("NIC found, calling bcmsdh_probe...\n")); @@ -121,7 +122,6 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) } } - /* devices we support, null terminated */ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, @@ -169,13 +169,6 @@ sdioh_sdmmc_osfree(sdioh_info_t *sd) sdos = (struct sdos_info *)sd->sdos_info; MFREE(sd->osh, sdos, sizeof(struct sdos_info)); } -#if defined(OOB_INTR_ONLY) -int -sdioh_mmc_irq(int irq) -{ - return (MSM_GPIO_TO_INT(irq)); -} -#endif /* defined(OOB_INTR_ONLY) */ /* Interrupt enable/disable */ SDIOH_API_RC diff --git a/bcm4329/src/bcmsdio/sys/bcmsdspi.c b/bcm4329/src/bcmsdio/sys/bcmsdspi.c index 206f34e..636539b 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdspi.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdspi.c @@ -1,7 +1,7 @@ /* * Broadcom BCMSDH to SPI Protocol Conversion Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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: bcmsdspi.c,v 1.14.4.2.4.4.6.4 2009/04/13 19:18:36 Exp $ + * $Id: bcmsdspi.c,v 1.14.4.2.4.4.6.5 2010/03/10 03:09:48 Exp $ */ #include <typedefs.h> @@ -57,6 +57,7 @@ uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */ 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 */ +uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ uint sd_toctl = 7; diff --git a/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c index 1046a17..e2e0ca6 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c @@ -1,7 +1,7 @@ /* * Broadcom SPI Host Controller Driver - Linux Per-port * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd.c b/bcm4329/src/bcmsdio/sys/bcmsdstd.c index 51ff4af..0b1b575 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdstd.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdstd.c @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.14 2009/10/08 20:05:30 Exp $ + * $Id: bcmsdstd.c,v 1.64.4.1.4.4.2.17 2010/03/10 03:09:48 Exp $ */ #include <typedefs.h> @@ -38,7 +38,8 @@ #include <pcicfg.h> -#define SD_PAGE 4096 +#define SD_PAGE_BITS 12 +#define SD_PAGE (1 << SD_PAGE_BITS) #include <bcmsdstd.h> @@ -58,16 +59,21 @@ uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ uint sd_power = 1; /* Default to SD Slot powered ON */ uint sd_clock = 1; /* Default to SD Clock turned ON */ +uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ +uint8 sd_dma_mode = DMA_MODE_SDMA; /* Default to SDMA for now */ uint sd_toctl = 7; static bool trap_errs = FALSE; +static const char *dma_mode_description[] = { "PIO", "SDMA", "ADMA1", "32b ADMA2", "64b ADMA2" }; + /* Prototypes */ static bool sdstd_start_clock(sdioh_info_t *sd, uint16 divisor); static bool sdstd_start_power(sdioh_info_t *sd); static bool sdstd_bus_width(sdioh_info_t *sd, int width); static int sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode); +static int sdstd_set_dma_mode(sdioh_info_t *sd, int8 dma_mode); static int sdstd_card_enablefuncs(sdioh_info_t *sd); static void sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count); static int sdstd_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg); @@ -84,6 +90,14 @@ static int sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg); static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize); static void sd_map_dma(sdioh_info_t * sd); static void sd_unmap_dma(sdioh_info_t * sd); +static void sd_clear_adma_dscr_buf(sdioh_info_t *sd); +static void sd_fill_dma_data_buf(sdioh_info_t *sd, uint8 data); +static void sd_create_adma_descriptor(sdioh_info_t *sd, + uint32 index, uint32 addr_phys, + uint16 length, uint16 flags); +static void sd_dump_adma_dscr(sdioh_info_t *sd); +static void sdstd_dumpregs(sdioh_info_t *sd); + /* * Private register access routines. @@ -205,15 +219,10 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) /* Set defaults */ sd->sd_blockmode = TRUE; sd->use_client_ints = TRUE; - sd->sd_use_dma = TRUE; + sd->sd_dma_mode = sd_dma_mode; if (!sd->sd_blockmode) - sd->sd_use_dma = 0; - - if (sd->sd_use_dma) { - OSL_DMADDRWIDTH(osh, 32); - sd_map_dma(sd); - } + sd->sd_dma_mode = DMA_MODE_NONE; if (sdstd_driver_init(sd) != SUCCESS) { /* If host CPU was reset without resetting SD bus or @@ -234,6 +243,11 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) } } + OSL_DMADDRWIDTH(osh, 32); + + /* Always map DMA buffers, so we can switch between DMA modes. */ + sd_map_dma(sd); + if (sdstd_register_irq(sd, irq) != SUCCESS) { sd_err(("%s: sdstd_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); sdstd_free_irq(sd->irq, sd); @@ -344,7 +358,7 @@ const bcm_iovar_t sdioh_iovars[] = { {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, + {"sd_dma", IOV_DMA, 0, IOVT_UINT32, 0 }, #ifdef BCMSDYIELD {"sd_yieldcpu", IOV_YIELDCPU, 0, IOVT_BOOL, 0 }, {"sd_minyield", IOV_MINYIELD, 0, IOVT_UINT32, 0 }, @@ -429,7 +443,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, si->sd_blockmode = (bool)int_val; /* Haven't figured out how to make non-block mode with DMA */ if (!si->sd_blockmode) - si->sd_use_dma = 0; + si->sd_dma_mode = DMA_MODE_NONE; break; #ifdef BCMSDYIELD @@ -503,12 +517,13 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, } case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; + int_val = (int32)si->sd_dma_mode; bcopy(&int_val, arg, val_size); break; case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; + si->sd_dma_mode = (char)int_val; + sdstd_set_dma_mode(si, si->sd_dma_mode); break; case IOV_GVAL(IOV_USEINTS): @@ -764,7 +779,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte); - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg)) != SUCCESS) { + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg)) != SUCCESS) { sdstd_unlock(sd); return status; } @@ -821,6 +836,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint bool fifo = (fix_inc == SDIOH_DATA_FIX); uint8 *localbuf = NULL, *tmpbuf = NULL; uint tmplen = 0; + bool local_blockmode = sd->sd_blockmode; sdstd_lock(sd); @@ -838,7 +854,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint * Both: leftovers are handled last (will be sent via bytemode). */ while (buflen > 0) { - if (sd->sd_blockmode) { + if (local_blockmode) { /* Max xfer is Page size */ len = MIN(SD_PAGE, buflen); @@ -870,7 +886,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint return SDIOH_API_RC_FAIL; } - if (sd->sd_blockmode) { + if (local_blockmode) { if ((func == SDIO_FUNC_1) && ((tmplen % 4) == 3) && (rw == SDIOH_WRITE)) { if (localbuf) MFREE(sd->osh, localbuf, len); @@ -952,6 +968,11 @@ int sdstd_abort(sdioh_info_t *sd, uint func) if (GFIELD(plain_intstatus, INTSTAT_CMD_COMPLETE)) { sd_err(("SDSTD_ABORT: CMD COMPLETE SET BEFORE COMMAND GIVEN!!!\n")); } + if (GFIELD(plain_intstatus, INTSTAT_CARD_REMOVAL)) { + sd_err(("SDSTD_ABORT: INTSTAT_CARD_REMOVAL\n")); + err = BCME_NODEVICE; + goto done; + } } /* Issue the command */ @@ -1060,6 +1081,9 @@ int sdstd_abort(sdioh_info_t *sd, uint func) } done: + if (err == BCME_NODEVICE) + return err; + sdstd_wreg8(sd, SD_SoftwareReset, SFIELD(SFIELD(0, SW_RESET_DAT, 1), SW_RESET_CMD, 1)); @@ -1200,6 +1224,7 @@ sdstd_reset(sdioh_info_t *sd, bool host_reset, bool client_reset) /* A reset should reset bus back to 1 bit mode */ sd->sd_mode = SDIOH_MODE_SD1; + sdstd_set_dma_mode(sd, sd->sd_dma_mode); } sdstd_unlock(sd); return TRUE; @@ -1324,7 +1349,8 @@ sdstd_host_init(sdioh_info_t *sd) num_slots = 1; first_bar = 0; - sd->sd_blockmode = FALSE; + /* Controller supports ADMA2, so turn it on here. */ + sd->sd_dma_mode = DMA_MODE_ADMA2; } /* Map in each slot on the board and query it to see if a @@ -1401,22 +1427,17 @@ sdstd_host_init(sdioh_info_t *sd) sd->caps = sdstd_rreg(sd, SD_Capabilities); /* Cache this for later use */ sd->curr_caps = sdstd_rreg(sd, SD_MaxCurCap); - if (!GFIELD(sd->caps, CAP_DMA)) { - sd_err(("SD HOST CAPS: No SDMA Support! Disabling DMA\n")); - sd->sd_use_dma = FALSE; - sd->sd_blockmode = FALSE; - } + sdstd_set_dma_mode(sd, sd->sd_dma_mode); sdstd_reset(sd, 1, 0); /* Read SD4/SD1 mode */ if ((reg8 = sdstd_rreg8(sd, SD_HostCntrl))) { - if (reg8 & SD4_MODE) + if (reg8 & SD4_MODE) { sd_err(("%s: Host cntrlr already in 4 bit mode: 0x%x\n", __FUNCTION__, reg8)); - else - sd_err(("%s: Error! reg 0x28 should be 0 = 0x%x\n", __FUNCTION__, reg8)); + } } /* Default power on mode is SD1 */ @@ -1440,7 +1461,7 @@ get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp) retries = CMD5_RETRIES; do { *cmd_rsp = 0; - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_5, *cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_5, *cmd_arg)) != SUCCESS) { sd_err(("%s: CMD5 failed\n", __FUNCTION__)); return status; @@ -1496,7 +1517,7 @@ sdstd_client_init(sdioh_info_t *sd) /* In SPI mode, issue CMD0 first */ if (sd->sd_mode == SDIOH_MODE_SPI) { cmd_arg = 0; - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_0, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_0, cmd_arg)) != SUCCESS) { sd_err(("BCMSDIOH: cardinit: CMD0 failed!\n")); return status; @@ -1508,7 +1529,7 @@ sdstd_client_init(sdioh_info_t *sd) /* Card is operational. Ask it to send an RCA */ cmd_arg = 0; - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_3, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_3, cmd_arg)) != SUCCESS) { sd_err(("%s: CMD3 failed!\n", __FUNCTION__)); return status; @@ -1534,7 +1555,7 @@ sdstd_client_init(sdioh_info_t *sd) /* Select the card */ cmd_arg = SFIELD(0, CMD7_RCA, sd->card_rca); - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_7, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_7, cmd_arg)) != SUCCESS) { sd_err(("%s: CMD7 failed!\n", __FUNCTION__)); return status; @@ -1656,6 +1677,86 @@ sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) return BCME_OK; } +/* Select DMA Mode: + * If dma_mode == DMA_MODE_AUTO, pick the "best" mode. + * Otherwise, pick the selected mode if supported. + * If not supported, use PIO mode. + */ +static int +sdstd_set_dma_mode(sdioh_info_t *sd, int8 dma_mode) +{ + uint8 reg8, dma_sel_bits = SDIOH_SDMA_MODE; + int8 prev_dma_mode = sd->sd_dma_mode; + + switch (prev_dma_mode) { + case DMA_MODE_AUTO: + sd_dma(("%s: Selecting best DMA mode supported by controller.\n", + __FUNCTION__)); + if (GFIELD(sd->caps, CAP_ADMA2)) { + sd->sd_dma_mode = DMA_MODE_ADMA2; + dma_sel_bits = SDIOH_ADMA2_MODE; + } else if (GFIELD(sd->caps, CAP_ADMA1)) { + sd->sd_dma_mode = DMA_MODE_ADMA1; + dma_sel_bits = SDIOH_ADMA1_MODE; + } else if (GFIELD(sd->caps, CAP_DMA)) { + sd->sd_dma_mode = DMA_MODE_SDMA; + } else { + sd->sd_dma_mode = DMA_MODE_NONE; + } + break; + case DMA_MODE_NONE: + sd->sd_dma_mode = DMA_MODE_NONE; + break; + case DMA_MODE_SDMA: + if (GFIELD(sd->caps, CAP_DMA)) { + sd->sd_dma_mode = DMA_MODE_SDMA; + } else { + sd_err(("%s: SDMA not supported by controller.\n", __FUNCTION__)); + sd->sd_dma_mode = DMA_MODE_NONE; + } + break; + case DMA_MODE_ADMA1: + if (GFIELD(sd->caps, CAP_ADMA1)) { + sd->sd_dma_mode = DMA_MODE_ADMA1; + dma_sel_bits = SDIOH_ADMA1_MODE; + } else { + sd_err(("%s: ADMA1 not supported by controller.\n", __FUNCTION__)); + sd->sd_dma_mode = DMA_MODE_NONE; + } + break; + case DMA_MODE_ADMA2: + if (GFIELD(sd->caps, CAP_ADMA2)) { + sd->sd_dma_mode = DMA_MODE_ADMA2; + dma_sel_bits = SDIOH_ADMA2_MODE; + } else { + sd_err(("%s: ADMA2 not supported by controller.\n", __FUNCTION__)); + sd->sd_dma_mode = DMA_MODE_NONE; + } + break; + case DMA_MODE_ADMA2_64: + sd_err(("%s: 64b ADMA2 not supported by driver.\n", __FUNCTION__)); + sd->sd_dma_mode = DMA_MODE_NONE; + break; + default: + sd_err(("%s: Unsupported DMA Mode %d requested.\n", __FUNCTION__, + prev_dma_mode)); + sd->sd_dma_mode = DMA_MODE_NONE; + break; + } + + /* clear SysAddr, only used for SDMA */ + sdstd_wreg(sd, SD_SysAddr, 0); + + sd_err(("%s: %s mode selected.\n", __FUNCTION__, dma_mode_description[sd->sd_dma_mode])); + + reg8 = sdstd_rreg8(sd, SD_HostCntrl); + reg8 = SFIELD(reg8, HOST_DMA_SEL, dma_sel_bits); + sdstd_wreg8(sd, SD_HostCntrl, reg8); + sd_dma(("%s: SD_HostCntrl=0x%02x\n", __FUNCTION__, reg8)); + + return BCME_OK; +} + bool sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) @@ -1942,7 +2043,7 @@ sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0); - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg)) != SUCCESS) return status; @@ -1973,7 +2074,7 @@ sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint /* sdstd_cmd_issue() returns with the command complete bit * in the ISR already cleared */ - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_53, cmd_arg)) != SUCCESS) return status; @@ -2115,7 +2216,7 @@ sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uin cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE); cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff); - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg)) != SUCCESS) return status; @@ -2138,7 +2239,7 @@ sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uin /* sdstd_cmd_issue() returns with the command complete bit * in the ISR already cleared */ - if ((status = sdstd_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg)) + if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_53, cmd_arg)) != SUCCESS) return status; @@ -2338,7 +2439,7 @@ sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg) cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL); cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd); - use_dma = sdioh_info->sd_use_dma && GFIELD(cmd_arg, CMD53_BLK_MODE); + use_dma = USE_DMA(sdioh_info) && GFIELD(cmd_arg, CMD53_BLK_MODE); if (GFIELD(cmd_arg, CMD53_BLK_MODE)) { uint16 blocksize; @@ -2347,22 +2448,46 @@ sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg) ASSERT(sdioh_info->sd_blockmode); + func = GFIELD(cmd_arg, CMD53_FUNCTION); + blocksize = MIN((int)sdioh_info->data_xfer_count, + sdioh_info->client_block_size[func]); + blockcount = GFIELD(cmd_arg, CMD53_BYTE_BLK_CNT); + /* data_xfer_cnt is already setup so that for multiblock mode, * it is the entire buffer length. For non-block or single block, * it is < 64 bytes */ if (use_dma) { - sd_info(("%s: Previous SysAddr reg was 0x%x now 0x%x\n", - __FUNCTION__, sdstd_rreg(sdioh_info, SD_SysAddr), - (uint32)sdioh_info->dma_phys)); + switch (sdioh_info->sd_dma_mode) { + case DMA_MODE_SDMA: + sd_dma(("%s: SDMA: SysAddr reg was 0x%x now 0x%x\n", + __FUNCTION__, sdstd_rreg(sdioh_info, SD_SysAddr), + (uint32)sdioh_info->dma_phys)); sdstd_wreg(sdioh_info, SD_SysAddr, sdioh_info->dma_phys); + break; + case DMA_MODE_ADMA1: + case DMA_MODE_ADMA2: + sd_dma(("%s: ADMA: Using ADMA\n", __FUNCTION__)); + sd_create_adma_descriptor(sdioh_info, 0, + sdioh_info->dma_phys, blockcount*blocksize, + ADMA2_ATTRIBUTE_VALID | ADMA2_ATTRIBUTE_END | + ADMA2_ATTRIBUTE_INT | ADMA2_ATTRIBUTE_ACT_TRAN); + /* Dump descriptor if DMA debugging is enabled. */ + if (sd_msglevel & SDH_DMA_VAL) { + sd_dump_adma_dscr(sdioh_info); + } + + sdstd_wreg(sdioh_info, SD_ADMA_SysAddr, + sdioh_info->adma2_dscr_phys); + break; + default: + sd_err(("%s: unsupported DMA mode %d.\n", + __FUNCTION__, sdioh_info->sd_dma_mode)); + break; + } } - func = GFIELD(cmd_arg, CMD53_FUNCTION); - blocksize = MIN((int)sdioh_info->data_xfer_count, - sdioh_info->client_block_size[func]); - blockcount = GFIELD(cmd_arg, CMD53_BYTE_BLK_CNT); - sd_trace(("%s: Writing Block count %d, block size %d bytes\n", + sd_trace(("%s: Setting block count %d, block size %d bytes\n", __FUNCTION__, blockcount, blocksize)); sdstd_wreg16(sdioh_info, SD_BlockSize, blocksize); sdstd_wreg16(sdioh_info, SD_BlockCount, blockcount); @@ -2464,6 +2589,7 @@ sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg) if (sdioh_info->polled_mode) { uint16 int_reg = 0; int retries = RETRIES_LARGE; + do { int_reg = sdstd_rreg16(sdioh_info, SD_IntrStatus); } while (--retries && @@ -2532,7 +2658,7 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n if (read) sd->r_cnt++; else sd->t_cnt++; local_blockmode = sd->sd_blockmode; - local_dma = sd->sd_use_dma; + local_dma = USE_DMA(sd); /* Don't bother with block mode on small xfers */ if (nbytes < sd->client_block_size[func]) { @@ -2635,6 +2761,7 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n __FUNCTION__, read ? "Read" : "Write", int_reg, sdstd_rreg16(sd, SD_ErrorIntrStatus), sdstd_rreg(sd, SD_PresentState))); + sdstd_dumpregs(sd); sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg); return (ERROR); } @@ -2723,6 +2850,7 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n sdstd_rreg(sd, SD_PresentState), int_reg, sdstd_rreg16(sd, SD_ErrorIntrStatus), nbytes, sd->r_cnt, sd->t_cnt)); + sdstd_dumpregs(sd); return ERROR; } @@ -2793,18 +2921,210 @@ int sdioh_sdio_reset(sdioh_info_t *si) static void sd_map_dma(sdioh_info_t * sd) { - if (sd->sd_use_dma == FALSE) - return; - if ((sd->dma_buf = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE, &sd->dma_phys, - 0x12, 12)) == NULL) { + + void *va; + + if ((va = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE, + &sd->dma_start_phys, 0x12, 12)) == NULL) { + sd->sd_dma_mode = DMA_MODE_NONE; + sd->dma_start_buf = 0; + sd->dma_buf = (void *)0; + sd->dma_phys = 0; + sd->alloced_dma_size = SD_PAGE; sd_err(("%s: DMA_ALLOC failed. Disabling DMA support.\n", __FUNCTION__)); - sd->sd_use_dma = FALSE; + } else { + sd->dma_start_buf = va; + sd->dma_buf = (void *)ROUNDUP((uintptr)va, SD_PAGE); + sd->dma_phys = ROUNDUP((sd->dma_start_phys), SD_PAGE); + sd->alloced_dma_size = SD_PAGE; + sd_err(("%s: Mapped DMA Buffer %dbytes @virt/phys: %p/0x%lx\n", + __FUNCTION__, sd->alloced_dma_size, sd->dma_buf, sd->dma_phys)); + sd_fill_dma_data_buf(sd, 0xA5); + } + + if ((va = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE, + &sd->adma2_dscr_start_phys, 0x12, 12)) == NULL) { + sd->sd_dma_mode = DMA_MODE_NONE; + sd->adma2_dscr_start_buf = 0; + sd->adma2_dscr_buf = (void *)0; + sd->adma2_dscr_phys = 0; + sd->alloced_adma2_dscr_size = 0; + sd_err(("%s: DMA_ALLOC failed for descriptor buffer. " + "Disabling DMA support.\n", __FUNCTION__)); + } else { + sd->adma2_dscr_start_buf = va; + sd->adma2_dscr_buf = (void *)ROUNDUP((uintptr)va, SD_PAGE); + sd->adma2_dscr_phys = ROUNDUP((sd->adma2_dscr_start_phys), SD_PAGE); + sd->alloced_adma2_dscr_size = SD_PAGE; } + + sd_err(("%s: Mapped ADMA2 Descriptor Buffer %dbytes @virt/phys: %p/0x%lx\n", + __FUNCTION__, sd->alloced_adma2_dscr_size, sd->adma2_dscr_buf, + sd->adma2_dscr_phys)); + sd_clear_adma_dscr_buf(sd); } + static void sd_unmap_dma(sdioh_info_t * sd) { - if (sd->sd_use_dma == FALSE) - return; - DMA_FREE_CONSISTENT(sd->osh, sd->dma_buf, SD_PAGE, sd->dma_phys, 0x12); + if (sd->dma_start_buf) { + DMA_FREE_CONSISTENT(sd->osh, sd->dma_start_buf, sd->alloced_dma_size, + sd->dma_start_phys, 0x12); + } + + if (sd->adma2_dscr_start_buf) { + DMA_FREE_CONSISTENT(sd->osh, sd->adma2_dscr_start_buf, sd->alloced_adma2_dscr_size, + sd->adma2_dscr_start_phys, 0x12); + } +} + +static void sd_clear_adma_dscr_buf(sdioh_info_t *sd) +{ + bzero((char *)sd->adma2_dscr_buf, SD_PAGE); + sd_dump_adma_dscr(sd); +} + +static void sd_fill_dma_data_buf(sdioh_info_t *sd, uint8 data) +{ + memset((char *)sd->dma_buf, data, SD_PAGE); +} + + +static void sd_create_adma_descriptor(sdioh_info_t *sd, uint32 index, + uint32 addr_phys, uint16 length, uint16 flags) +{ + adma2_dscr_32b_t *adma2_dscr_table; + adma1_dscr_t *adma1_dscr_table; + + adma2_dscr_table = sd->adma2_dscr_buf; + adma1_dscr_table = sd->adma2_dscr_buf; + + switch (sd->sd_dma_mode) { + case DMA_MODE_ADMA2: + sd_dma(("%s: creating ADMA2 descriptor for index %d\n", + __FUNCTION__, index)); + + adma2_dscr_table[index].phys_addr = addr_phys; + adma2_dscr_table[index].len_attr = length << 16; + adma2_dscr_table[index].len_attr |= flags; + break; + case DMA_MODE_ADMA1: + /* ADMA1 requires two descriptors, one for len + * and the other for data transfer + */ + index <<= 1; + + sd_dma(("%s: creating ADMA1 descriptor for index %d\n", + __FUNCTION__, index)); + + adma1_dscr_table[index].phys_addr_attr = length << 12; + adma1_dscr_table[index].phys_addr_attr |= (ADMA1_ATTRIBUTE_ACT_SET | + ADMA2_ATTRIBUTE_VALID); + adma1_dscr_table[index+1].phys_addr_attr = addr_phys & 0xFFFFF000; + adma1_dscr_table[index+1].phys_addr_attr |= (flags & 0x3f); + break; + default: + sd_err(("%s: cannot create ADMA descriptor for DMA mode %d\n", + __FUNCTION__, sd->sd_dma_mode)); + break; + } +} + + +static void sd_dump_adma_dscr(sdioh_info_t *sd) +{ + adma2_dscr_32b_t *adma2_dscr_table; + adma1_dscr_t *adma1_dscr_table; + uint32 i = 0; + uint16 flags; + char flags_str[32]; + + ASSERT(sd->adma2_dscr_buf != NULL); + + adma2_dscr_table = sd->adma2_dscr_buf; + adma1_dscr_table = sd->adma2_dscr_buf; + + switch (sd->sd_dma_mode) { + case DMA_MODE_ADMA2: + sd_err(("ADMA2 Descriptor Table (%dbytes) @virt/phys: %p/0x%lx\n", + SD_PAGE, sd->adma2_dscr_buf, sd->adma2_dscr_phys)); + sd_err((" #[Descr VA ] Buffer PA | Len | Flags (5:4 2 1 0)" + " |\n")); + while (adma2_dscr_table->len_attr & ADMA2_ATTRIBUTE_VALID) { + flags = adma2_dscr_table->len_attr & 0xFFFF; + sprintf(flags_str, "%s%s%s%s", + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_LINK) ? "LINK " : + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_TRAN) ? "TRAN " : + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_NOP) ? "NOP " : "RSV ", + (flags & ADMA2_ATTRIBUTE_INT ? "INT " : " "), + (flags & ADMA2_ATTRIBUTE_END ? "END " : " "), + (flags & ADMA2_ATTRIBUTE_VALID ? "VALID" : "")); + sd_err(("%2d[0x%p]: 0x%08x | 0x%04x | 0x%04x (%s) |\n", + i, adma2_dscr_table, adma2_dscr_table->phys_addr, + adma2_dscr_table->len_attr >> 16, flags, flags_str)); + i++; + + /* Follow LINK descriptors or skip to next. */ + if ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_LINK) { + adma2_dscr_table = phys_to_virt( + adma2_dscr_table->phys_addr); + } else { + adma2_dscr_table++; + } + + } + break; + case DMA_MODE_ADMA1: + sd_err(("ADMA1 Descriptor Table (%dbytes) @virt/phys: %p/0x%lx\n", + SD_PAGE, sd->adma2_dscr_buf, sd->adma2_dscr_phys)); + sd_err((" #[Descr VA ] Buffer PA | Flags (5:4 2 1 0) |\n")); + + for (i = 0; adma1_dscr_table->phys_addr_attr & ADMA2_ATTRIBUTE_VALID; i++) { + flags = adma1_dscr_table->phys_addr_attr & 0x3F; + sprintf(flags_str, "%s%s%s%s", + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_LINK) ? "LINK " : + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_TRAN) ? "TRAN " : + ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_NOP) ? "NOP " : "SET ", + (flags & ADMA2_ATTRIBUTE_INT ? "INT " : " "), + (flags & ADMA2_ATTRIBUTE_END ? "END " : " "), + (flags & ADMA2_ATTRIBUTE_VALID ? "VALID" : "")); + sd_err(("%2d[0x%p]: 0x%08x | 0x%04x | (%s) |\n", + i, adma1_dscr_table, + adma1_dscr_table->phys_addr_attr & 0xFFFFF000, + flags, flags_str)); + + /* Follow LINK descriptors or skip to next. */ + if ((flags & ADMA2_ATTRIBUTE_ACT_LINK) == + ADMA2_ATTRIBUTE_ACT_LINK) { + adma1_dscr_table = phys_to_virt( + adma1_dscr_table->phys_addr_attr & 0xFFFFF000); + } else { + adma1_dscr_table++; + } + } + break; + default: + sd_err(("Unknown DMA Descriptor Table Format.\n")); + break; + } +} + +static void sdstd_dumpregs(sdioh_info_t *sd) +{ + sd_err(("IntrStatus: 0x%04x ErrorIntrStatus 0x%04x\n", + sdstd_rreg16(sd, SD_IntrStatus), + sdstd_rreg16(sd, SD_ErrorIntrStatus))); + sd_err(("IntrStatusEnable: 0x%04x ErrorIntrStatusEnable 0x%04x\n", + sdstd_rreg16(sd, SD_IntrStatusEnable), + sdstd_rreg16(sd, SD_ErrorIntrStatusEnable))); + sd_err(("IntrSignalEnable: 0x%04x ErrorIntrSignalEnable 0x%04x\n", + sdstd_rreg16(sd, SD_IntrSignalEnable), + sdstd_rreg16(sd, SD_ErrorIntrSignalEnable))); } diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c index 5746b08..ad6d660 100644 --- a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c +++ b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver - linux portion * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/bcmsdio/sys/bcmspibrcm.c b/bcm4329/src/bcmsdio/sys/bcmspibrcm.c new file mode 100644 index 0000000..0f131a4 --- /dev/null +++ b/bcm4329/src/bcmsdio/sys/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 <typedefs.h> + +#include <bcmdevs.h> +#include <bcmendian.h> +#include <bcmutils.h> +#include <osl.h> +#include <hndsoc.h> +#include <siutils.h> +#include <sbchipc.h> +#include <sbsdio.h> +#include <spid.h> + +#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ +#include <sdiovar.h> /* ioctl/iovars */ +#include <sdio.h> + +#include <pcicfg.h> + + +#include <bcmspibrcm.h> +#include <bcmspi.h> + +#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/bcm4329/src/branding.inc b/bcm4329/src/branding.inc index 8491edd..9633ac8 100644 --- a/bcm4329/src/branding.inc +++ b/bcm4329/src/branding.inc @@ -1,4 +1,4 @@ -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/exe/GNUmakefile b/bcm4329/src/dhd/exe/GNUmakefile index 240189b..901f2ca 100644 --- a/bcm4329/src/dhd/exe/GNUmakefile +++ b/bcm4329/src/dhd/exe/GNUmakefile @@ -2,7 +2,7 @@ # GNUmakefile for dhd/exe # (Basically a copy of wl/exe linux portion.) # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you @@ -49,7 +49,7 @@ CFLAGS += -DBCMSPI #----------------------------------------------------------- # Linux build # -ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le android"),) +ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le linuxarm_omap android"),) # $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files DHD_OBJS := dhdu.o dhdu_linux.o bcmutils.o miniopt.o @@ -63,6 +63,10 @@ endif # extra warnings CFLAGS += -Wextra $(CUSTOM_FLAGS) +ifeq ($(TARGETENV), linuxarm_omap) +CFLAGS += -DBGBRD +endif + vpath %.c $(SRCBASE)/shared all: $(DHD_EXE) diff --git a/bcm4329/src/dhd/exe/dhdu.c b/bcm4329/src/dhd/exe/dhdu.c index 372f732..afd8b61 100644 --- a/bcm4329/src/dhd/exe/dhdu.c +++ b/bcm4329/src/dhd/exe/dhdu.c @@ -1,7 +1,7 @@ /* * Common code for dhd utility, hacked from wl utility * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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: dhdu.c,v 1.52.2.10.2.6.2.11 2009/09/25 00:32:00 Exp $ + * $Id: dhdu.c,v 1.52.2.10.2.6.2.14 2010/01/19 07:24:15 Exp $ */ /* For backwards compatibility, the absense of the define 'BWL_NO_FILESYSTEM_SUPPORT' @@ -71,6 +71,7 @@ static cmd_func_t dhd_pktgen; static cmd_func_t dhd_sprom; static cmd_func_t dhd_sdreg; static cmd_func_t dhd_sd_msglevel, dhd_sd_blocksize, dhd_sd_mode, dhd_sd_reg; +static cmd_func_t dhd_dma_mode; static cmd_func_t dhd_membytes, dhd_download, dhd_upload, dhd_vars, dhd_idleclock, dhd_idletime; static cmd_func_t dhd_logstamp; @@ -114,6 +115,8 @@ cmd_t dhd_cmds[] = { "get version information" }, { "msglevel", dhd_msglevel, DHD_GET_VAR, DHD_SET_VAR, "get/set message bits" }, + { "wlmsglevel", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "get/set wl message(in dhd) bits" }, { "bcmerrorstr", dhd_var_getandprintstr, DHD_GET_VAR, -1, "errorstring"}, { "wdtick", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, @@ -225,8 +228,8 @@ cmd_t dhd_cmds[] = { "g/set blockmode"}, { "sd_ints", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, "g/set client ints"}, - { "sd_dma", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, - "g/set dma usage"}, + { "sd_dma", dhd_dma_mode, DHD_GET_VAR, DHD_SET_VAR, + "g/set dma usage: [PIO | SDMA | ADMA1 | ADMA2]"}, { "sd_yieldcpu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, "allow blocking (yield of CPU) on data xfer"}, { "sd_minyield", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, @@ -670,6 +673,7 @@ static dbg_msg_t dhd_sd_msgs[] = { {SDH_DATA_VAL, "data"}, {SDH_CTRL_VAL, "control"}, {SDH_LOG_VAL, "log"}, + {SDH_DMA_VAL, "dma"}, {0, NULL} }; @@ -763,6 +767,56 @@ dhd_sd_mode(void *wl, cmd_t *cmd, char **argv) return (ret); } +static int +dhd_dma_mode(void *wl, cmd_t *cmd, char **argv) +{ + int ret; + int argc; + int dmamode; + + /* arg count */ + for (argc = 0; argv[argc]; argc++); + argc--; + + if (argv[1]) { + if (!stricmp(argv[1], "pio")) { + strcpy(argv[1], "0"); + } else if (!strcmp(argv[1], "0")) { + } else if (!stricmp(argv[1], "dma")) { + strcpy(argv[1], "1"); + } else if (!stricmp(argv[1], "sdma")) { + strcpy(argv[1], "1"); + } else if (!strcmp(argv[1], "1")) { + } else if (!stricmp(argv[1], "adma1")) { + strcpy(argv[1], "2"); + } else if (!stricmp(argv[1], "adma")) { + strcpy(argv[1], "3"); + } else if (!stricmp(argv[1], "adma2")) { + strcpy(argv[1], "3"); + } else { + return USAGE_ERROR; + } + + ret = dhd_var_setint(wl, cmd, argv); + + } else { + if ((ret = dhd_var_get(wl, cmd, argv))) { + return (ret); + } else { + dmamode = *(int32*)buf; + + printf("DMA Mode is: %s\n", + dmamode == 0 ? "PIO" + : dmamode == 1 ? "SDMA" + : dmamode == 2 ? "ADMA1" + : dmamode == 3 ? "ADMA2" + : "Unknown"); + } + } + + return (ret); +} + static int dhd_sdreg(void *dhd, cmd_t *cmd, char **argv) diff --git a/bcm4329/src/dhd/exe/dhdu.h b/bcm4329/src/dhd/exe/dhdu.h index 97a56d6..44f0368 100644 --- a/bcm4329/src/dhd/exe/dhdu.h +++ b/bcm4329/src/dhd/exe/dhdu.h @@ -1,7 +1,7 @@ /* * Common code for dhd utility, hacked from wl utility * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/exe/dhdu_cmd.h b/bcm4329/src/dhd/exe/dhdu_cmd.h index 8e1f642..220bbda 100644 --- a/bcm4329/src/dhd/exe/dhdu_cmd.h +++ b/bcm4329/src/dhd/exe/dhdu_cmd.h @@ -1,7 +1,7 @@ /* * Command structure for dhd command line utility, copied from wl utility * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/exe/dhdu_linux.c b/bcm4329/src/dhd/exe/dhdu_linux.c index b4dcbc7..e00c460 100644 --- a/bcm4329/src/dhd/exe/dhdu_linux.c +++ b/bcm4329/src/dhd/exe/dhdu_linux.c @@ -1,7 +1,7 @@ /* * Linux port of dhd command line utility, hacked from wl utility. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/linux/Makefile b/bcm4329/src/dhd/linux/Makefile index 89300a1..19d81d2 100644 --- a/bcm4329/src/dhd/linux/Makefile +++ b/bcm4329/src/dhd/linux/Makefile @@ -1,7 +1,7 @@ # GNU Makefile for Broadcom Dongle Host Driver # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you @@ -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: Makefile,v 1.55.2.6.2.10.6.24 2009/10/22 18:40:45 Exp $ +# $Id: Makefile,v 1.55.2.6.2.10.6.27 2010/02/24 02:54:05 Exp $ # # Try a couple of places for LINUXDIR if not specified @@ -70,7 +70,7 @@ OBJCOPY := $(CROSS_COMPILE)objcopy ifeq ($(SRCBASE),) SRCBASE := $(shell /bin/pwd)/../.. endif -vpath %.c $(SRCBASE)/dhd/sys $(SRCBASE)/shared $(SRCBASE)/bcmsdio/sys $(SRCBASE)/wl/sys +vpath %.c $(SRCBASE)/dhd/sys $(SRCBASE)/shared $(SRCBASE)/bcmsdio/sys $(SRCBASE)/wl/sys $(SRCBASE)/crypto ## Initialize DFLAGS DFLAGS := @@ -211,8 +211,14 @@ ifneq ($(findstring -sdstd-,$(TARGET)-),) DFLAGS += -DBCMSDIO -DBCMSDIOH_STD CFILES += dhd_sdio.c bcmsdh.c bcmsdstd.c bcmsdstd_linux.c bcmsdh_linux.c endif +ifneq ($(findstring -softap-,-$(TARGET)-),) +DFLAGS += -DSOFTAP +CFILES += sha1.c md5.c +endif ifneq ($(findstring -oob-,-$(TARGET)-),) DFLAGS += -DOOB_INTR_ONLY +DFLAGS += -DHW_OOB +DFLAGS += -DMMC_SDIO_ABORT else ifneq ($(findstring -sdmmc-,-$(TARGET)-),) DFLAGS += -DSDIO_ISR_THREAD @@ -246,10 +252,14 @@ MODULES := dhd.o ifeq ($(BCM_KVER), 2.6) ##Kernel module names in 2.6 kernel have .ko suffix KMODULES:=dhd.ko + ifneq ($(findstring -nexus-,$(TARGET)-),) + KMODULES:=bcm4329.ko + endif else KMODULES:=$(MODULES) endif + # host options HOSTCC := $(CC) ifneq ($(BCM_KVER), 2.6) @@ -266,7 +276,9 @@ TARGETS := \ dhd-cdc-usb dhd-cdc-sdstd \ dhd-cdc-sdspi-pci dhd-cdc-sdmmc-gpl dhd-cdc-sdmmc-oob-gpl \ dhd-cdc-usb-apsta dhd-cdc-usb-gpl \ - dhd-cdc-sdstd-apsta + dhd-cdc-sdstd-apsta \ + dhd-cdc-sdmmc-softap-gpl + TARGETS += \ @@ -311,9 +323,9 @@ ifneq ($(BCM_KVER), 2.6) endif $(MAKE) -C $(OBJDIR) -f $(SRCBASE)/dhd/linux/Makefile SRCBASE=$(SRCBASE) modules ifeq ($(BCM_KVER), 2.6) - $(OBJCOPY) --strip-unneeded $(OBJDIR)/dhd.ko $(OBJDIR)/dhd.ko.stripped + $(OBJCOPY) --strip-unneeded $(OBJDIR)/$(KMODULES) $(OBJDIR)/$(KMODULES).stripped else - $(OBJCOPY) --strip-unneeded $(OBJDIR)/dhd.o $(OBJDIR)/dhd.o.stripped + $(OBJCOPY) --strip-unneeded $(OBJDIR)/$(MODULES) $(OBJDIR)/$(MODULES).stripped endif dep: $(foreach file,$(CFILES),.$(file).depend) @@ -330,7 +342,7 @@ else modules: $(MODULES) endif -dhd.o: $(OFILES) +$(MODULES): $(OFILES) $(LD) $(LDFLAGS) -o $@ $^ ifeq ($(BCM_KVER), 2.6) diff --git a/bcm4329/src/dhd/linux/makefile.26 b/bcm4329/src/dhd/linux/makefile.26 index 86c220b..eceee8e 100644 --- a/bcm4329/src/dhd/linux/makefile.26 +++ b/bcm4329/src/dhd/linux/makefile.26 @@ -2,7 +2,7 @@ # Makefile fragment for Linux 2.6 # Broadcom DHD Driver # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2010, Broadcom Corporation # # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h index 38baa8a..faf016f 100644 --- a/bcm4329/src/dhd/sys/dhd.h +++ b/bcm4329/src/dhd/sys/dhd.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.25 2009/10/27 04:41:56 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.29 2010/02/23 06:58:21 Exp $ */ /**************** @@ -46,23 +46,25 @@ #include <linux/ethtool.h> #include <asm/uaccess.h> #include <asm/unaligned.h> - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) +#include <linux/wakelock.h> +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ /* The kernel threading is sdio-specific */ #else /* LINUX */ #define ENOMEM 1 -#define EFAULT 2 +#define EFAULT 2 #define EINVAL 3 -#define EIO 4 +#define EIO 4 #define ETIMEDOUT 5 -#define ERESTARTSYS 6 +#define ERESTARTSYS 6 #endif /* LINUX */ #include <wlioctl.h> -#ifdef NDIS60 +#if defined(NDIS60) #include <wdf.h> #include <WdfMiniport.h> -#endif /* NDIS60 */ +#endif /* Forward decls */ struct dhd_bus; @@ -147,9 +149,12 @@ typedef struct dhd_pub { int dongle_error; uint8 country_code[WLC_CNTRY_BUF_SZ]; +#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) */ } dhd_pub_t; -#ifdef NDIS60 +#if defined(NDIS60) typedef struct _wdf_device_info { dhd_pub_t *dhd; @@ -158,7 +163,7 @@ typedef struct _wdf_device_info { WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) -#endif /* NDIS60 */ +#endif /* NDIS60 && !UNDERC_CE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) @@ -166,7 +171,7 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) #define _DHD_PM_RESUME_WAIT(a, b) do {\ int retry = 0; \ while (dhd_mmc_suspend && retry++ != b) { \ - wait_event_interruptible_timeout(a, FALSE, HZ/100); \ + wait_event_timeout(a, FALSE, HZ/100); \ } \ } while (0) #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) @@ -178,7 +183,7 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) #define SPINWAIT_SLEEP(a, exp, us) do { \ uint countdown = (us) + 9; \ while ((exp) && (countdown >= 10)) { \ - wait_event_interruptible_timeout(a, FALSE, HZ/100); \ + wait_event_timeout(a, FALSE, HZ/100); \ countdown -= 10; \ } \ } while (0) @@ -203,11 +208,41 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ #define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ -/* Wakelock Functions */ -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); +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) */ +} + typedef struct dhd_if_event { uint8 ifidx; @@ -275,6 +310,8 @@ 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 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); #if defined(OOB_INTR_ONLY) extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); #endif /* defined(OOB_INTR_ONLY) */ @@ -321,6 +358,7 @@ extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); extern uint dhd_bus_status(dhd_pub_t *dhdp); extern int dhd_bus_start(dhd_pub_t *dhdp); +extern void print_buf(void *pbuf, int len, int bytes_per_line); typedef enum cust_gpio_modes { @@ -329,6 +367,7 @@ typedef enum cust_gpio_modes { WLAN_POWER_ON, WLAN_POWER_OFF } cust_gpio_modes_t; +extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); /* * Insmod parameters for debug/test */ @@ -337,6 +376,10 @@ typedef enum cust_gpio_modes { extern uint dhd_watchdog_ms; +#if defined(DHD_DEBUG) +extern uint wl_msg_level; +#endif /* DHD_DEBUG */ + /* Use interrupts */ extern uint dhd_intr; diff --git a/bcm4329/src/dhd/sys/dhd_bus.h b/bcm4329/src/dhd/sys/dhd_bus.h index 93392f9..7156543 100644 --- a/bcm4329/src/dhd/sys/dhd_bus.h +++ b/bcm4329/src/dhd/sys/dhd_bus.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/sys/dhd_cdc.c b/bcm4329/src/dhd/sys/dhd_cdc.c index 935a766..77da0ea 100644 --- a/bcm4329/src/dhd/sys/dhd_cdc.c +++ b/bcm4329/src/dhd/sys/dhd_cdc.c @@ -1,7 +1,7 @@ /* * DHD Protocol Module for CDC and BDC. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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_cdc.c,v 1.22.4.2.4.7.2.30 2009/10/28 21:38:04 Exp $ + * $Id: dhd_cdc.c,v 1.22.4.2.4.7.2.34 2010/01/21 22:08:34 Exp $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -73,12 +73,9 @@ 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 @@ -87,9 +84,7 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ - ret = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); - dhd_os_wake_unlock(dhd); - return ret; + return dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); } static int @@ -141,9 +136,9 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) msg->cmd = htol32(cmd); msg->len = htol32(len); - flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - msg->flags = htol32(flags); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); CDC_SET_IF_IDX(msg, ifidx); + msg->flags = htol32(msg->flags); if (buf) memcpy(prot->buf, buf, len); @@ -208,9 +203,9 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) msg->cmd = htol32(cmd); msg->len = htol32(len); - flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET; - msg->flags |= htol32(flags); + msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET; CDC_SET_IF_IDX(msg, ifidx); + msg->flags |= htol32(msg->flags); if (buf) memcpy(prot->buf, buf, len); @@ -288,7 +283,6 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) ret = 0; else { cdc_ioctl_t *msg = &prot->msg; - CDC_SET_IF_IDX(msg, ifidx); ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ } @@ -634,7 +628,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf))) < 0) { DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); dhd_os_proto_unblock(dhd); - return -BCME_NOTUP; + return BCME_NOTUP; } memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); @@ -737,7 +731,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); if (mask_size != pattern_size) { - printk("Mask and pattern not the same size\n"); + DHD_ERROR(("Mask and pattern not the same size\n")); dhd_os_proto_unblock(dhd); return -EINVAL; } diff --git a/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c index f840aba..ae0c3fb 100644 --- a/bcm4329/src/dhd/sys/dhd_common.c +++ b/bcm4329/src/dhd/sys/dhd_common.c @@ -1,7 +1,7 @@ /* * Broadcom Dongle Host Driver (DHD), common DHD core. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.37 2009/10/22 14:47:18 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.41 2010/02/24 01:52:41 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -79,7 +79,7 @@ const bcm_iovar_t dhd_iovars[] = { {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, #ifdef DHD_DEBUG {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -#endif +#endif /* DHD_DEBUG */ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, @@ -101,16 +101,8 @@ dhd_common_init(void) * first time that the driver is initialized vs subsequent initializations. */ dhd_msg_level = DHD_ERROR_VAL; -#ifdef CONFIG_BCM4329_FW_PATH - strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); -#else fw_path[0] = '\0'; -#endif -#ifdef CONFIG_BCM4329_NVRAM_PATH - strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1); -#else nv_path[0] = '\0'; -#endif } static int @@ -197,6 +189,7 @@ 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; @@ -553,6 +546,8 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) event_name = event_names[i].event_name; } + DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type)); + if (flags & WLC_EVENT_MSG_LINK) link = TRUE; if (flags & WLC_EVENT_MSG_GROUP) @@ -891,3 +886,25 @@ wl_event_to_host_order(wl_event_msg_t *evt) evt->datalen = ntoh32(evt->datalen); evt->version = ntoh16(evt->version); } + +void print_buf(void *pbuf, int len, int bytes_per_line) +{ + int i, j = 0; + unsigned char *buf = pbuf; + + if (bytes_per_line == 0) { + bytes_per_line = len; + } + + for (i = 0; i < len; i++) { + printf("%2.2x", *buf++); + j++; + if (j == bytes_per_line) { + printf("\n"); + j = 0; + } else { + printf(":"); + } + } + printf("\n"); +} diff --git a/bcm4329/src/dhd/sys/dhd_custom_gpio.c b/bcm4329/src/dhd/sys/dhd_custom_gpio.c index 9d655f9..cb67ae2 100644 --- a/bcm4329/src/dhd/sys/dhd_custom_gpio.c +++ b/bcm4329/src/dhd/sys/dhd_custom_gpio.c @@ -1,6 +1,6 @@ /* * Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2009, Broadcom Corporation +* Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.3 2009/10/14 04:29:34 Exp $ +* $Id: dhd_custom_gpio.c,v 1.1.4.6 2010/02/19 22:56:49 Exp $ */ @@ -42,7 +42,6 @@ extern void bcm_wlan_power_off(int); extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ - #ifdef CUSTOMER_HW2 int wifi_set_carddetect(int on); int wifi_set_power(int on, unsigned long msec); @@ -55,6 +54,10 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr); extern int sdioh_mmc_irq(int irq); #endif /* (BCMLXSDMMC) */ +#ifdef CUSTOMER_HW3 +#include <mach/gpio.h> +#endif + /* Customer specific Host GPIO defintion */ static int dhd_oob_gpio_num = -1; /* GG 19 */ @@ -63,10 +66,12 @@ MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) { - int host_oob_irq; + int host_oob_irq = 0; + #ifdef CUSTOMER_HW2 host_oob_irq = wifi_get_irq_number(irq_flags_ptr); -#else + +#else /* for NOT CUSTOMER_HW2 */ #if defined(CUSTOM_OOB_GPIO_NUM) if (dhd_oob_gpio_num < 0) { dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; @@ -74,17 +79,23 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) #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__)); + WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", + __FUNCTION__)); return (dhd_oob_gpio_num); } - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", \ + WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", __FUNCTION__, dhd_oob_gpio_num)); - /* TODO : move it mmc specific code */ - host_oob_irq = sdioh_mmc_irq(dhd_oob_gpio_num); -#endif +#if defined CUSTOMER_HW + host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num); +#elif defined CUSTOMER_HW3 + gpio_request(dhd_oob_gpio_num, "oob irq"); + host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); + gpio_direction_input(dhd_oob_gpio_num); +#endif /* CUSTOMER_HW */ +#endif /* CUSTOMER_HW2 */ + return (host_oob_irq); } #endif /* defined(OOB_INTR_ONLY) */ diff --git a/bcm4329/src/dhd/sys/dhd_dbg.h b/bcm4329/src/dhd/sys/dhd_dbg.h index f7f0c35..852f3c2 100644 --- a/bcm4329/src/dhd/sys/dhd_dbg.h +++ b/bcm4329/src/dhd/sys/dhd_dbg.h @@ -1,7 +1,7 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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_dbg.h,v 1.5.6.2.4.2.14.2 2009/05/20 19:41:53 Exp $ + * $Id: dhd_dbg.h,v 1.5.6.2.4.2.14.6 2010/02/23 05:36:53 Exp $ */ #ifndef _dhd_dbg_ @@ -29,7 +29,8 @@ #ifdef DHD_DEBUG -#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) 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) @@ -57,7 +58,7 @@ #else /* DHD_DEBUG */ -#define DHD_ERROR(args) printk args +#define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0) #define DHD_TRACE(args) #define DHD_INFO(args) #define DHD_DATA(args) diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c index df46938..38a1a11 100644 --- a/bcm4329/src/dhd/sys/dhd_linux.c +++ b/bcm4329/src/dhd/sys/dhd_linux.c @@ -2,7 +2,7 @@ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface * Basically selected code segments from usb-cdc.c and usb-rndis.c * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.46 2009/10/28 10:35:11 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.60.4.1 2010/03/16 03:29:40 Exp $ */ #ifdef CONFIG_WIFI_CONTROL_FUNC @@ -57,11 +57,6 @@ #include <dhd_bus.h> #include <dhd_proto.h> #include <dhd_dbg.h> -#include <wl_iw.h> -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif -#include <linux/freezer.h> #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) #include <linux/wifi_tiwlan.h> @@ -115,13 +110,12 @@ int wifi_set_reset(int on, unsigned long msec) mdelay(msec); return 0; } - static int wifi_probe(struct platform_device *pdev) { struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - DHD_TRACE(("## %s\n", __FUNCTION__)); + printk("## %s\n", __FUNCTION__); wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); wifi_control_data = wifi_ctrl; @@ -137,7 +131,7 @@ static int wifi_remove(struct platform_device *pdev) struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - DHD_TRACE(("## %s\n", __FUNCTION__)); + printk("## %s\n", __FUNCTION__); wifi_control_data = wifi_ctrl; wifi_set_carddetect(0); /* CardDetect (1->0) */ @@ -154,7 +148,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 = { @@ -254,15 +248,6 @@ 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; - /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -286,6 +271,7 @@ char nvram_path[MOD_PARAM_PATHLEN]; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 struct semaphore dhd_registration_sem; +#define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */ #endif /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); @@ -315,6 +301,10 @@ module_param(dhd_dpc_prio, int, 0); extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); +/* Network inteface name */ +char iface_name[IFNAMSIZ]; +module_param_string(iface_name, iface_name, IFNAMSIZ, 0); + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ @@ -712,11 +702,15 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) return ret; } +#ifdef SOFTAP +extern struct net_device *ap_net_dev; +#endif + static void dhd_op_if(dhd_if_t *ifp) { dhd_info_t *dhd; - int ret = 0; + int ret = 0, err = 0; ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ @@ -743,15 +737,29 @@ dhd_op_if(dhd_if_t *ifp) if (ret == 0) { strcpy(ifp->net->name, ifp->name); memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); - if (dhd_net_attach(&dhd->pub, ifp->idx) != 0) { - DHD_ERROR(("%s: dhd_net_attach failed\n", __FUNCTION__)); + if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { + DHD_ERROR(("%s: dhd_net_attach failed, err %d\n", + __FUNCTION__, err)); ret = -EOPNOTSUPP; - } else + } else { +#ifdef SOFTAP + /* semaphore that the soft AP CODE waits on */ + extern struct semaphore ap_eth_sema; + + /* save ptr to wl0.1 netdev for use in wl_iw.c */ + ap_net_dev = ifp->net; + /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ + up(&ap_eth_sema); +#endif + DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", + current->pid, ifp->net->name)); ifp->state = 0; + } } break; case WLC_E_IF_DEL: if (ifp->net != NULL) { + 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 */ @@ -763,12 +771,23 @@ dhd_op_if(dhd_if_t *ifp) break; } + if (ret < 0) { - if (ifp->net) + + if (ifp->net) { + free_netdev(ifp->net); + } + dhd->iflist[ifp->idx] = NULL; 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 */ +#endif /* SOFTAP */ } + } static int @@ -777,12 +796,9 @@ _dhd_sysioc_thread(void *data) dhd_info_t *dhd = (dhd_info_t *)data; int i; - set_freezable(); - DAEMONIZE("dhd_sysioc"); while (down_interruptible(&dhd->sysioc_sem) == 0) { - dhd_os_wake_lock(&dhd->pub); for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { if (dhd->iflist[i]->state) @@ -797,7 +813,6 @@ _dhd_sysioc_thread(void *data) } } } - dhd_os_wake_unlock(&dhd->pub); } complete_and_exit(&dhd->sysioc_exited, 0); } @@ -871,6 +886,7 @@ 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 */ @@ -890,7 +906,6 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) /* Reject if down */ if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { DHD_ERROR(("%s: xmit rejected due to dhd bus down status \n", __FUNCTION__)); - netif_stop_queue(net); return -ENODEV; } @@ -1051,7 +1066,6 @@ 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 @@ -1118,6 +1132,7 @@ 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 @@ -1131,17 +1146,17 @@ dhd_watchdog_thread(void *data) } #endif /* DHD_SCHED */ - set_freezable(); - DAEMONIZE("dhd_watchdog"); /* Run until signal received */ while (1) { if (down_interruptible (&dhd->watchdog_sem) == 0) { - dhd_os_wake_lock(&dhd->pub); - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - + 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++; @@ -1149,12 +1164,12 @@ dhd_watchdog_thread(void *data) 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); } @@ -1175,12 +1190,8 @@ dhd_watchdog(ulong data) dhd->pub.tickcnt++; /* Reschedule the watchdog */ -#if defined(CONTINUOUS_WATCHDOG) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); -#else if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); -#endif /* defined(CONTINUOUS_WATCHDOG) */ } static int @@ -1188,6 +1199,7 @@ 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 */ @@ -1200,8 +1212,6 @@ dhd_dpc_thread(void *data) } #endif /* DHD_SCHED */ - set_freezable(); - DAEMONIZE("dhd_dpc"); /* Run until signal received */ @@ -1209,21 +1219,22 @@ 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); } - else { - dhd_os_wake_unlock(&dhd->pub); - } + WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_DPC); } 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); } @@ -1248,7 +1259,6 @@ 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; @@ -1473,6 +1483,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); + if (ifidx == DHD_BAD_IF) return -1; @@ -1564,9 +1575,13 @@ 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); done: if (!bcmerror && buf && ioc.buf) { if (copy_to_user(ioc.buf, buf, buflen)) @@ -1611,8 +1626,6 @@ dhd_open(struct net_device *net) #endif int ifidx; - wl_control_wl_start(net); /* start if needed */ - ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); @@ -1744,15 +1757,26 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) memcpy(netdev_priv(net), &dhd, sizeof(dhd)); dhd->pub.osh = osh; + /* Set network interface name if it was provided as module parameter */ + if (iface_name[0]) { + int len; + char ch; + strncpy(net->name, iface_name, IFNAMSIZ); + net->name[IFNAMSIZ - 1] = 0; + len = strlen(net->name); + ch = net->name[len - 1]; + if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) + strcat(net->name, "%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); @@ -1762,15 +1786,6 @@ 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 - /* Link to info module */ dhd->pub.info = dhd; @@ -1844,6 +1859,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #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) */ + /* 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; @@ -1876,12 +1894,19 @@ 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 */ @@ -1896,7 +1921,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_sync(&dhd->timer); + del_timer(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); return -ENODEV; @@ -1908,7 +1933,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_sync(&dhd->timer); + del_timer(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); return -ENODEV; @@ -1945,7 +1970,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, @@ -1953,7 +1978,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 = { @@ -1961,10 +1986,9 @@ 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 - +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { @@ -1975,10 +1999,11 @@ 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; + net = dhd->iflist[ifidx]->net; ASSERT(net); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ASSERT(!net->open); net->get_stats = dhd_get_stats; net->do_ioctl = dhd_ioctl_entry; @@ -1996,7 +2021,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) /* * device functions for the primary interface only */ -#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 @@ -2022,6 +2047,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) #endif /* WIRELESS_EXT > 12 */ #endif /* CONFIG_WIRELESS_EXT */ + dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen; memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); @@ -2034,6 +2060,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) printf("%s: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name, 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]); + wl_iw_iscan_set_scan_broadcast_prep(net, 1); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 up(&dhd_registration_sem); @@ -2041,7 +2068,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) 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; @@ -2069,7 +2096,7 @@ dhd_bus_detach(dhd_pub_t *dhdp) #endif /* defined(OOB_INTR_ONLY) */ /* Clear the watchdog timer */ - del_timer_sync(&dhd->timer); + del_timer(&dhd->timer); dhd->wd_timer_valid = FALSE; } } @@ -2091,14 +2118,6 @@ dhd_detach(dhd_pub_t *dhdp) #if defined(CONFIG_HAS_EARLYSUSPEND) unregister_early_suspend(&dhd->early_suspend); #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ -#ifdef CONFIG_WIRELESS_EXT - /* Attach and link in the iw */ - wl_iw_detach(); -#endif - if (dhd->sysioc_pid >= 0) { - KILL_PROC(dhd->sysioc_pid, SIGTERM); - wait_for_completion(&dhd->sysioc_exited); - } for (i = 1; i < DHD_MAX_IFS; i++) if (dhd->iflist[i]) @@ -2106,7 +2125,7 @@ dhd_detach(dhd_pub_t *dhdp) 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) { @@ -2115,38 +2134,60 @@ 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->dpc_pid >= 0) - { - KILL_PROC(dhd->dpc_pid, SIGTERM); - wait_for_completion(&dhd->dpc_exited); - } - else - tasklet_kill(&dhd->tasklet); + 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); - dhd_bus_detach(dhdp); + if (dhd->sysioc_pid >= 0) { + KILL_PROC(dhd->sysioc_pid, SIGTERM); + wait_for_completion(&dhd->sysioc_exited); + } + + dhd_bus_detach(dhdp); - if (dhdp->prot) - dhd_prot_detach(dhdp); + if (dhdp->prot) + dhd_prot_detach(dhdp); + +#ifdef CONFIG_WIRELESS_EXT + /* Attach and link in the iw */ + wl_iw_detach(); +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - unregister_pm_notifier(&dhd_sleep_pm_notifier); + unregister_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - 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)); - } + 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)); } } +} +static void __exit +dhd_module_cleanup(void) +{ + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + dhd_bus_unregister(); +#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) @@ -2168,7 +2209,6 @@ dhd_module_init(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); @@ -2178,18 +2218,19 @@ dhd_module_init(void) error = wifi_add_dev(); if (error) { DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); - goto fail_0; + goto faild; } /* Waiting callback after platform_driver_register is done or exit with error */ - 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; + 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; } #endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 sema_init(&dhd_registration_sem, 0); #endif @@ -2199,51 +2240,28 @@ dhd_module_init(void) printf("\n%s\n", dhd_version); else { DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto fail_1; + goto faild; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 /* * Wait till MMC sdio_register_driver callback called and made driver attach. * It's needed to make sync up exit from dhd insmod and * Kernel MMC sdio device callback registration */ - if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(10000)) != 0) { + if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { error = -EINVAL; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); - goto fail_2; + dhd_bus_unregister(); } #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) */ - - /* Call customer gpio to turn off power with WL_REG_ON signal */ - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); - - return error; -} - -static void __exit -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - dhd_bus_unregister(); -#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 */ +faild: + /* turn off power and exit */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); + return -EINVAL; } - module_init(dhd_module_init); module_exit(dhd_module_cleanup); @@ -2330,36 +2348,38 @@ void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - -#if !defined(CONTINUOUS_WATCHDOG) static uint save_dhd_watchdog_ms = 0; -#endif /* !defined(CONTINUOUS_WATCHDOG) */ - -#if defined(CONTINUOUS_WATCHDOG) - dhd_watchdog_ms = (uint)wdtick; - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd_info_t *dhd = (dhd_info_t *)pub->info; - dhd->wd_timer_valid = TRUE; -#else /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { - del_timer_sync(&dhd->timer); + del_timer(&dhd->timer); dhd->wd_timer_valid = FALSE; save_dhd_watchdog_ms = wdtick; return; } if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + 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->wd_timer_valid = TRUE; save_dhd_watchdog_ms = wdtick; } -#endif /* defined(CONTINUTOUS_WATCHDOG) */ } void * @@ -2414,7 +2434,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 @@ -2427,7 +2447,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 @@ -2563,16 +2583,15 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - /* Turning off watchdog */ - if (flag) - dhd_os_wd_timer(&dhd->pub, 0); + /* Turning off watchdog */ + if (flag) + dhd_os_wd_timer(&dhd->pub, 0); dhd_bus_devreset(&dhd->pub, flag); - /* Turning on watchdog back */ - if (!flag) - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - + /* Turning on watchdog back */ + if (!flag) + dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); return 1; @@ -2613,120 +2632,3 @@ dhd_wait_pend8021x(struct net_device *dev) } return pend; } - -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 >> 1)); -#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; -} diff --git a/bcm4329/src/dhd/sys/dhd_linux_sched.c b/bcm4329/src/dhd/sys/dhd_linux_sched.c index 3189123..480b416 100644 --- a/bcm4329/src/dhd/sys/dhd_linux_sched.c +++ b/bcm4329/src/dhd/sys/dhd_linux_sched.c @@ -1,7 +1,7 @@ /* * Expose some of the kernel scheduler routines * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/sys/dhd_proto.h b/bcm4329/src/dhd/sys/dhd_proto.h index 1e2401a..79584d6 100644 --- a/bcm4329/src/dhd/sys/dhd_proto.h +++ b/bcm4329/src/dhd/sys/dhd_proto.h @@ -4,7 +4,7 @@ * Provides type definitions and function prototypes used to link the * DHD OS, bus, and protocol modules. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c index 427600f..b006623 100644 --- a/bcm4329/src/dhd/sys/dhd_sdio.c +++ b/bcm4329/src/dhd/sys/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.89 2009/10/28 05:49:40 Exp $ + * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.98 2010/02/01 05:22:19 Exp $ */ #include <typedefs.h> @@ -293,10 +293,8 @@ static int tx_packets[NUMPRIO]; /* Deferred transmit */ const uint dhd_deferred_tx = 1; -#if !defined(CONTINUOUS_WATCHDOG) extern uint dhd_watchdog_ms; extern void dhd_os_wd_timer(void *bus, uint wdtick); -#endif /* !defined(CONTINUOUS_WATCHDOG) */ /* Tx/Rx bounds */ uint dhd_txbound; @@ -514,9 +512,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) /* Go to pending and await interrupt if appropriate */ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { - DHD_INFO(("CLKCTL: set PENDING\n")); - bus->clkstate = CLK_PENDING; - /* Allow only clock-available interrupt */ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); if (err) { @@ -527,6 +522,8 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; 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 */ @@ -692,12 +689,9 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) /* Early exit if we're already there */ if (bus->clkstate == target) { - if (target == CLK_AVAIL) { -#if !defined(CONTINUOUS_WATCHDOG) + if (target == CLK_AVAIL) dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -#endif /* !defined(CONTINUOUS_WATCHDOG) */ bus->activity = TRUE; - } return BCME_OK; } @@ -708,9 +702,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) dhdsdio_sdclk(bus, TRUE); /* Now request HT Avail on the backplane */ dhdsdio_htclk(bus, TRUE, pendok); -#if !defined(CONTINUOUS_WATCHDOG) dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -#endif /* !defined(CONTINUOUS_WATCHDOG) */ bus->activity = TRUE; break; @@ -723,9 +715,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) else DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", bus->clkstate, target)); -#if !defined(CONTINUOUS_WATCHDOG) dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -#endif /* !defined(CONTINUOUS_WATCHDOG) */ break; case CLK_NONE: @@ -734,9 +724,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) dhdsdio_htclk(bus, FALSE, FALSE); /* Now remove the SD clock */ dhdsdio_sdclk(bus, FALSE); -#if !defined(CONTINUOUS_WATCHDOG) dhd_os_wd_timer(bus->dhd, 0); -#endif /* !defined(CONTINUOUS_WATCHDOG) */ break; } #ifdef DHD_DEBUG @@ -858,7 +846,7 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) /* Turn off our contribution to the HT clock request */ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -#endif /* defined(HW_OOB) */ +#endif /* !defined(HW_OOB) */ } #endif /* defined(OOB_INTR_ONLY) */ @@ -1597,11 +1585,6 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s uint32 sdaddr; uint dsize; - if (size % 4) { - size += 3; - size &= 0xFFFFFFFC; - } - /* Determine initial transfer parameters */ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) @@ -3768,8 +3751,8 @@ dhdsdio_dpc(dhd_bus_t *bus) if (err) { DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); bus->dhd->busstate = DHD_BUS_DOWN; - } - ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); + }else + ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); #endif /* DHD_DEBUG */ /* Read CSR, if clock on switch to AVAIL, else ignore */ @@ -3943,8 +3926,8 @@ clkwait: /* Resched if events or tx frames are pending, else await next interrupt */ /* On failed register access, all bets are off: no resched or interrupts */ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { - DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", - __FUNCTION__)); + DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n", + __FUNCTION__, bcmsdh_regfail(sdh))); bus->dhd->busstate = DHD_BUS_DOWN; bus->intstatus = 0; } else if (bus->clkstate == CLK_PENDING) { @@ -3989,7 +3972,13 @@ void dhdsdio_isr(void *arg) { dhd_bus_t *bus = (dhd_bus_t*)arg; - bcmsdh_info_t *sdh = bus->sdh; + bcmsdh_info_t *sdh; + + if (!bus) { + DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); + return; + } + sdh = bus->sdh; if (bus->dhd->busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); @@ -4020,14 +4009,13 @@ 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 @@ -4537,12 +4525,13 @@ 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)) == -1) { - DHD_TRACE(("%s: warning : check if firmware was provided\n", __FUNCTION__)); - } - else if (ret == BCME_NOTUP) { - DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__)); + if ((ret = dhd_bus_start(bus->dhd)) != 0) { + DHD_ERROR(("%s: failed\n", __FUNCTION__)); goto fail; + if (ret == BCME_NOTUP) { + DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__)); + goto fail; + } } /* Ok, have the per-port tell the stack we're open for business */ if (dhd_net_attach(bus->dhd, 0) != 0) { @@ -4843,6 +4832,7 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ret = dhdsdio_download_firmware(bus, osh, bus->sdh); + return ret; } @@ -4852,13 +4842,12 @@ 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; } @@ -4872,6 +4861,10 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh) ASSERT(osh); + /* De-register interrupt handler */ + bcmsdh_intr_disable(bus->sdh); + bcmsdh_intr_dereg(bus->sdh); + if (bus->dhd) { dhdsdio_release_dongle(bus, osh); @@ -4882,9 +4875,6 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh) dhdsdio_release_malloc(bus, osh); - /* De-register interrupt handler */ - bcmsdh_intr_dereg(bus->sdh); - MFREE(osh, bus, sizeof(dhd_bus_t)); } @@ -5379,8 +5369,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Force flow control as protection when stop come before ifconfig_down */ dhd_txflowcontrol(bus->dhd, 0, ON); #endif /* !defined(IGNORE_ETH0_DOWN) */ - dhd_os_proto_block(dhdp); /* save country settinng if was pre-setup with priv ioctl */ + dhd_os_proto_block(dhdp); dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY, bus->dhd->country_code, sizeof(bus->dhd->country_code)); dhd_os_proto_unblock(dhdp); diff --git a/bcm4329/src/dongle/dngl_stats.h b/bcm4329/src/dongle/dngl_stats.h index c1776a8..e5db54e 100644 --- a/bcm4329/src/dongle/dngl_stats.h +++ b/bcm4329/src/dongle/dngl_stats.h @@ -2,7 +2,7 @@ * Common stats definitions for clients of dongle * ports * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/aidmp.h b/bcm4329/src/include/aidmp.h index 44b3de8..a927e5d 100644 --- a/bcm4329/src/include/aidmp.h +++ b/bcm4329/src/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmcdc.h b/bcm4329/src/include/bcmcdc.h index 641d755..c2a860b 100644 --- a/bcm4329/src/include/bcmcdc.h +++ b/bcm4329/src/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmdefs.h b/bcm4329/src/include/bcmdefs.h index ba7a9e4..67d1158 100644 --- a/bcm4329/src/include/bcmdefs.h +++ b/bcm4329/src/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,15 +20,38 @@ * Notwithstanding the above, under no circumstances may you combine this * 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: bcmdefs.h,v 13.38.4.10.2.7.6.10 2009/07/03 08:20:51 Exp $ + * $Id: bcmdefs.h,v 13.38.4.10.2.7.6.11 2010/02/01 05:51:55 Exp $ */ #ifndef _bcmdefs_h_ #define _bcmdefs_h_ + + + + + + +#define bcmreclaimed 0 +#define r2_reclaimed 0 +#define _data _data +#define _fn _fn +#define _data _data +#define _fn _fn +#define _fn _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn +#define CONST const + + + +#define _data _data +#define _fn _fn +#define _fn _fn #define STATIC static + #define SI_BUS 0 #define PCI_BUS 1 #define PCMCIA_BUS 2 diff --git a/bcm4329/src/include/bcmdevs.h b/bcm4329/src/include/bcmdevs.h index 80b2ea8..910e246 100644 --- a/bcm4329/src/include/bcmdevs.h +++ b/bcm4329/src/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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: bcmdevs.h,v 13.172.4.5.4.10.2.19 2009/09/18 23:51:17 Exp $ + * $Id: bcmdevs.h,v 13.172.4.5.4.10.2.29 2010/03/01 08:56:24 Exp $ */ @@ -58,6 +58,7 @@ #define BCM4329_D11NDUAL_ID 0x432e #define BCM4329_D11N2G_ID 0x432f #define BCM4329_D11N5G_ID 0x4330 +#define BCM4336_D11N_ID 0x4343 #define BCM4315_D11DUAL_ID 0x4334 #define BCM4315_D11G_ID 0x4335 #define BCM4315_D11A_ID 0x4336 @@ -90,6 +91,7 @@ #define BCM4325_CHIP_ID 0x4325 #define BCM4328_CHIP_ID 0x4328 #define BCM4329_CHIP_ID 0x4329 +#define BCM4336_CHIP_ID 0x4336 #define BCM4402_CHIP_ID 0x4402 #define BCM4704_CHIP_ID 0x4704 #define BCM4710_CHIP_ID 0x4710 diff --git a/bcm4329/src/include/bcmendian.h b/bcm4329/src/include/bcmendian.h index 38887df..ae46838 100644 --- a/bcm4329/src/include/bcmendian.h +++ b/bcm4329/src/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmpcispi.h b/bcm4329/src/include/bcmpcispi.h index e3be826..7d98fb7 100644 --- a/bcm4329/src/include/bcmpcispi.h +++ b/bcm4329/src/include/bcmpcispi.h @@ -1,7 +1,7 @@ /* * Broadcom PCI-SPI Host Controller Register Definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmperf.h b/bcm4329/src/include/bcmperf.h index dfc3f44..2a78784 100644 --- a/bcm4329/src/include/bcmperf.h +++ b/bcm4329/src/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdbus.h b/bcm4329/src/include/bcmsdbus.h index 0e629c0..b7b67bc 100644 --- a/bcm4329/src/include/bcmsdbus.h +++ b/bcm4329/src/include/bcmsdbus.h @@ -2,7 +2,7 @@ * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdh.h b/bcm4329/src/include/bcmsdh.h index f8ab8ab..f5dee5c 100644 --- a/bcm4329/src/include/bcmsdh.h +++ b/bcm4329/src/include/bcmsdh.h @@ -3,7 +3,7 @@ * export functions to client drivers * abstract OS and BUS specific details of SDIO * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdh_sdmmc.h b/bcm4329/src/include/bcmsdh_sdmmc.h index b572f34..4e6d1b5 100644 --- a/bcm4329/src/include/bcmsdh_sdmmc.h +++ b/bcm4329/src/include/bcmsdh_sdmmc.h @@ -1,7 +1,7 @@ /* * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdpcm.h b/bcm4329/src/include/bcmsdpcm.h index b63b1d3..450c9c3 100644 --- a/bcm4329/src/include/bcmsdpcm.h +++ b/bcm4329/src/include/bcmsdpcm.h @@ -2,7 +2,7 @@ * Broadcom SDIO/PCMCIA * Software-specific definitions shared between device and host side * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdspi.h b/bcm4329/src/include/bcmsdspi.h index b1e2be9..eaae10d 100644 --- a/bcm4329/src/include/bcmsdspi.h +++ b/bcm4329/src/include/bcmsdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmsdstd.h b/bcm4329/src/include/bcmsdstd.h index 7bffbad..974b3d4 100644 --- a/bcm4329/src/include/bcmsdstd.h +++ b/bcm4329/src/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,17 +21,18 @@ * 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.h,v 13.16.18.1.16.2 2008/09/30 17:14:16 Exp $ + * $Id: bcmsdstd.h,v 13.16.18.1.16.3 2009/12/10 01:09:23 Exp $ */ /* global msglevel for debug messages - bitvals come from sdiovar.h */ -#define sd_err(x) +#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) #define sd_trace(x) #define sd_info(x) #define sd_debug(x) #define sd_data(x) #define sd_ctrl(x) +#define sd_dma(x) #define sd_sync_dma(sd, read, nbytes) #define sd_init_dma(sd) @@ -78,8 +79,6 @@ extern void sdstd_osfree(sdioh_info_t *sd); #define RETRIES_LARGE 100000 #define RETRIES_SMALL 100 -#define USE_PIO 0x0 /* DMA or PIO */ -#define USE_DMA 0x1 #define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ #define USE_MULTIBLOCK 0x4 @@ -115,7 +114,6 @@ struct sdioh_info { 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 */ @@ -125,17 +123,64 @@ struct sdioh_info { int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ uint32 data_xfer_count; /* Current transfer */ uint16 card_rca; /* Current Address */ + int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ uint8 num_funcs; /* Supported funcs on client */ uint32 com_cis_ptr; uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - void *dma_buf; - ulong dma_phys; + void *dma_buf; /* DMA Buffer virtual address */ + ulong dma_phys; /* DMA Buffer physical address */ + void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ + ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ + + /* adjustments needed to make the dma align properly */ + void *dma_start_buf; + ulong dma_start_phys; + uint alloced_dma_size; + void *adma2_dscr_start_buf; + ulong adma2_dscr_start_phys; + uint alloced_adma2_dscr_size; + int r_cnt; /* rx count */ int t_cnt; /* tx_count */ bool got_hcint; /* local interrupt flag */ uint16 last_intrstatus; /* to cache intrstatus */ }; +#define DMA_MODE_NONE 0 +#define DMA_MODE_SDMA 1 +#define DMA_MODE_ADMA1 2 +#define DMA_MODE_ADMA2 3 +#define DMA_MODE_ADMA2_64 4 +#define DMA_MODE_AUTO -1 + +#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) + +/* SDIO Host Control Register DMA Mode Definitions */ +#define SDIOH_SDMA_MODE 0 +#define SDIOH_ADMA1_MODE 1 +#define SDIOH_ADMA2_MODE 2 +#define SDIOH_ADMA2_64_MODE 3 + +#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ +#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ +#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ +#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ +#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ +#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ +#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ +#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ + +/* ADMA2 Descriptor Table Entry for 32-bit Address */ +typedef struct adma2_dscr_32b { + uint32 len_attr; + uint32 phys_addr; +} adma2_dscr_32b_t; + +/* ADMA1 Descriptor Table Entry */ +typedef struct adma1_dscr { + uint32 phys_addr_attr; +} adma1_dscr_t; + /************************************************************ * Internal interfaces: per-port references into bcmsdstd.c */ diff --git a/bcm4329/src/include/bcmspi.h b/bcm4329/src/include/bcmspi.h index 0c46538..2e2bc93 100644 --- a/bcm4329/src/include/bcmspi.h +++ b/bcm4329/src/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/bcmspibrcm.h b/bcm4329/src/include/bcmspibrcm.h new file mode 100644 index 0000000..9dce878 --- /dev/null +++ b/bcm4329/src/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/bcm4329/src/include/bcmutils.h b/bcm4329/src/include/bcmutils.h index 93bf25f..7010838 100644 --- a/bcm4329/src/include/bcmutils.h +++ b/bcm4329/src/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * 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: bcmutils.h,v 13.184.4.6.2.1.18.22 2009/10/28 18:25:39 Exp $ + * $Id: bcmutils.h,v 13.184.4.6.2.1.18.24 2009/12/10 20:19:19 Exp $ */ @@ -338,8 +338,11 @@ extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool #define BCME_NOT_WME_ASSOCIATION -34 #define BCME_SDIO_ERROR -35 #define BCME_DONGLE_DOWN -36 -#define BCME_VERSION -37 -#define BCME_UNFINISHED -38 +#define BCME_VERSION -37 +#define BCME_TXFAIL -38 +#define BCME_RXFAIL -39 +#define BCME_NODEVICE -40 +#define BCME_UNFINISHED -41 #define BCME_LAST BCME_UNFINISHED @@ -381,8 +384,11 @@ extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool "Not WME Association", \ "SDIO Bus Error", \ "Dongle Not Accessible", \ - "Incorrect version", \ - "Command not finished" \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "Command not finished", \ } #ifndef ABS diff --git a/bcm4329/src/include/bcmwifi.h b/bcm4329/src/include/bcmwifi.h index 8f5f3dc..038aedc 100644 --- a/bcm4329/src/include/bcmwifi.h +++ b/bcm4329/src/include/bcmwifi.h @@ -3,7 +3,7 @@ * This header file housing the define and function prototype use by * both the wl driver, tools & Apps. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * Notwithstanding the above, under no circumstances may you combine this * 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: bcmwifi.h,v 1.15.30.1 2009/08/15 00:51:27 Exp $ + * $Id: bcmwifi.h,v 1.15.30.4 2010/03/10 20:10:52 Exp $ */ @@ -39,6 +39,7 @@ typedef uint16 chanspec_t; #define CH_EWA_VALID 0x04 #define CH_20MHZ_APART 4 #define CH_10MHZ_APART 2 +#define CH_5MHZ_APART 1 #define CH_MAX_2G_CHANNEL 14 #define WLC_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL #define MAXCHANNEL 224 @@ -113,6 +114,11 @@ typedef uint16 chanspec_t; #define CHSPEC_SB_NONE(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) #define CHSPEC_SB_UPPER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) #define CHSPEC_SB_LOWER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) +#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \ + (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ + (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK)))) + +#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G((chspec))? WLC_BAND_5G: WLC_BAND_2G) #define CHANSPEC_STR_LEN 8 diff --git a/bcm4329/src/include/dhdioctl.h b/bcm4329/src/include/dhdioctl.h index ee78c3d..706b4a8 100644 --- a/bcm4329/src/include/dhdioctl.h +++ b/bcm4329/src/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/epivers.h b/bcm4329/src/include/epivers.h index e16e102..8137f60 100644 --- a/bcm4329/src/include/epivers.h +++ b/bcm4329/src/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -31,18 +31,18 @@ #define EPI_MINOR_VERSION 218 -#define EPI_RC_NUMBER 161 +#define EPI_RC_NUMBER 204 -#define EPI_INCREMENTAL_NUMBER 0 +#define EPI_INCREMENTAL_NUMBER 1 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 161, 0 +#define EPI_VERSION 4, 218, 204, 1 -#define EPI_VERSION_NUM 0x04daa100 +#define EPI_VERSION_NUM 0x04dacc01 -#define EPI_VERSION_STR "4.218.161.0" -#define EPI_ROUTER_VERSION_STR "4.219.161.0" +#define EPI_VERSION_STR "4.218.204.1" +#define EPI_ROUTER_VERSION_STR "4.219.204.1" #endif diff --git a/bcm4329/src/include/hndpmu.h b/bcm4329/src/include/hndpmu.h index afd78d7..e5568e7 100644 --- a/bcm4329/src/include/hndpmu.h +++ b/bcm4329/src/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/hndsoc.h b/bcm4329/src/include/hndsoc.h index dcbab43..3542417 100644 --- a/bcm4329/src/include/hndsoc.h +++ b/bcm4329/src/include/hndsoc.h @@ -1,7 +1,7 @@ /* * Broadcom HND chip & on-chip-interconnect-related definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/linux_osl.h b/bcm4329/src/include/linux_osl.h index 98afe9c..c8c658e 100644 --- a/bcm4329/src/include/linux_osl.h +++ b/bcm4329/src/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/linuxver.h b/bcm4329/src/include/linuxver.h index a36de95..c329ec2 100644 --- a/bcm4329/src/include/linuxver.h +++ b/bcm4329/src/include/linuxver.h @@ -2,7 +2,7 @@ * Linux-specific abstractions to gain some independence from linux kernel versions. * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linuxver.h,v 13.38.8.1.8.3 2009/06/19 04:42:45 Exp $ + * $Id: linuxver.h,v 13.38.8.1.8.5 2010/02/04 13:47:16 Exp $ */ @@ -425,11 +425,22 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #define CHECKSUM_HW CHECKSUM_PARTIAL #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +#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)) #define KILL_PROC(pid, sig) \ { \ struct task_struct *tsk; \ - tsk = pid_task(find_vpid(pid), PIDTYPE_PID); \ + tsk = find_task_by_vpid(pid); \ if (tsk) send_sig(sig, tsk, 1); \ } #else @@ -438,6 +449,7 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) 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/bcm4329/src/include/miniopt.h b/bcm4329/src/include/miniopt.h index 91e6603..3667fb1 100644 --- a/bcm4329/src/include/miniopt.h +++ b/bcm4329/src/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/msgtrace.h b/bcm4329/src/include/msgtrace.h index d79a89e..1479086 100644 --- a/bcm4329/src/include/msgtrace.h +++ b/bcm4329/src/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/osl.h b/bcm4329/src/include/osl.h index 02b2b21..5599e53 100644 --- a/bcm4329/src/include/osl.h +++ b/bcm4329/src/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/packed_section_end.h b/bcm4329/src/include/packed_section_end.h index e455d69..5b61c18 100644 --- a/bcm4329/src/include/packed_section_end.h +++ b/bcm4329/src/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/packed_section_start.h b/bcm4329/src/include/packed_section_start.h index a15562e..cb93aa6 100644 --- a/bcm4329/src/include/packed_section_start.h +++ b/bcm4329/src/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/pcicfg.h b/bcm4329/src/include/pcicfg.h index 61c2f4a..898962c 100644 --- a/bcm4329/src/include/pcicfg.h +++ b/bcm4329/src/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/802.11.h b/bcm4329/src/include/proto/802.11.h index 217bd6c..3ef7de2 100644 --- a/bcm4329/src/include/proto/802.11.h +++ b/bcm4329/src/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.11 * - * $Id: 802.11.h,v 9.219.4.1.4.5.6.10 2009/07/09 10:15:09 Exp $ + * $Id: 802.11.h,v 9.219.4.1.4.5.6.11 2010/02/09 13:23:26 Exp $ */ @@ -361,15 +361,25 @@ BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { dot11_brcm_extch_ie_t extch_ie; } BWL_POST_PACKED_STRUCT; - -BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { - uint8 id; - uint8 len; +BWL_PRE_PACKED_STRUCT struct dot11_csa_body { uint8 mode; uint8 reg; uint8 channel; uint8 count; } BWL_POST_PACKED_STRUCT; + + +BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { + uint8 id; + uint8 len; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; + +BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { + uint8 category; + uint8 action; + struct dot11_csa_body b; +} BWL_POST_PACKED_STRUCT; typedef struct dot11_ext_csa dot11_ext_csa_ie_t; #define DOT11_EXT_CSA_IE_LEN 4 @@ -1025,7 +1035,8 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_ACTION_ID_HT_MIMO_PS 1 -#define DOT11_ACTION_ID_BSS_COEX_MNG 0 +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 #define DOT11_BA_ACTION_ADDBA_REQ 0 diff --git a/bcm4329/src/include/proto/802.11e.h b/bcm4329/src/include/proto/802.11e.h index 0c53530..1dd6f45 100644 --- a/bcm4329/src/include/proto/802.11e.h +++ b/bcm4329/src/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/802.1d.h b/bcm4329/src/include/proto/802.1d.h index efd7117..45c728b 100644 --- a/bcm4329/src/include/proto/802.1d.h +++ b/bcm4329/src/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/bcmeth.h b/bcm4329/src/include/proto/bcmeth.h index bd34a0b..fdb5a2a 100644 --- a/bcm4329/src/include/proto/bcmeth.h +++ b/bcm4329/src/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/bcmevent.h b/bcm4329/src/include/proto/bcmevent.h index 1791478..46c04d3 100644 --- a/bcm4329/src/include/proto/bcmevent.h +++ b/bcm4329/src/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/bcmip.h b/bcm4329/src/include/proto/bcmip.h index 9645016..9d2fd6f 100644 --- a/bcm4329/src/include/proto/bcmip.h +++ b/bcm4329/src/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/ethernet.h b/bcm4329/src/include/proto/ethernet.h index 05530d5..c2fc4bf 100644 --- a/bcm4329/src/include/proto/ethernet.h +++ b/bcm4329/src/include/proto/ethernet.h @@ -1,7 +1,7 @@ /* * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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: ethernet.h,v 9.45.56.3 2009/08/15 00:51:27 Exp $ + * $Id: ethernet.h,v 9.45.56.5 2010/02/22 22:04:36 Exp $ */ diff --git a/bcm4329/src/include/proto/sdspi.h b/bcm4329/src/include/proto/sdspi.h index 3c7bcf3..7739e68 100644 --- a/bcm4329/src/include/proto/sdspi.h +++ b/bcm4329/src/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/vlan.h b/bcm4329/src/include/proto/vlan.h index 2dda4d5..670bc44 100644 --- a/bcm4329/src/include/proto/vlan.h +++ b/bcm4329/src/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/proto/wpa.h b/bcm4329/src/include/proto/wpa.h index 4c50125..f5d0cd5 100644 --- a/bcm4329/src/include/proto/wpa.h +++ b/bcm4329/src/include/proto/wpa.h @@ -1,7 +1,7 @@ /* * Fundamental types and constants relating to WPA * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbchipc.h b/bcm4329/src/include/sbchipc.h index 80e6e56..8c8be26 100644 --- a/bcm4329/src/include/sbchipc.h +++ b/bcm4329/src/include/sbchipc.h @@ -7,7 +7,7 @@ * * $Id: sbchipc.h,v 13.103.2.5.4.5.2.9 2009/07/03 14:23:21 Exp $ * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -823,11 +823,70 @@ typedef volatile struct { +#define PMU1_PLL0_PLLCTL0 0 +#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 +#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 +#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 +#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 +#define PMU1_PLL0_PC0_BYPASS_SDMOD_MASK 0x10000000 +#define PMU1_PLL0_PC0_BYPASS_SDMOD_SHIFT 28 + + + +#define PMU1_PLL0_PLLCTL1 1 +#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff +#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 +#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 +#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 +#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 +#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 +#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 + #define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 #define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) #define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) +#define PMU1_PLL0_PLLCTL2 2 +#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff +#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 +#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 +#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 +#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 +#define PMU1_PLL0_PC2_NDIV_MODE_INT 0 + +#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 +#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 +#define PMU1_PLL0_PC2_NDIV_MODE_MASH_1BY8 3 +#define PMU1_PLL0_PC2_NDIV_MODE_MFB_1BY8 4 + +#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 + + +#define PMU1_PLL0_PLLCTL3 3 +#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 + + +#define PMU1_PLL0_PLLCTL4 4 +#define PMU1_PLL0_PC4_KVCO_XS_MASK 0x38000000 +#define PMU1_PLL0_PC4_KVCO_XS_SHIFT 27 + + + +#define PMU1_PLL0_PLLCTL5 5 +#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 +#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 +#define PMU1_PLL0_PC5_PLL_CTRL_37_32_MASK 0x0000003f +#define PMU1_PLL0_PC5_PLL_CTRL_37_32_SHIFT 0 +#define PMU1_PLL0_PC5_VCO_RNG_MASK 0x000000C0 +#define PMU1_PLL0_PC5_VCO_RNG_SHIFT 6 + + + #define PMU2_PHY_PLL_PLLCTL 4 #define PMU2_SI_PLL_PLLCTL 10 @@ -1001,6 +1060,58 @@ typedef volatile struct { #define CST4315_CBUCK_MODE_BURST 0x00000400 #define CST4315_CBUCK_MODE_LPBURST 0x00000c00 + +#define RES4319_CBUCK_LPOM 1 +#define RES4319_CBUCK_BURST 2 +#define RES4319_CBUCK_PWM 3 +#define RES4319_CLDO_PU 4 +#define RES4319_PALDO_PU 5 +#define RES4319_ILP_REQUEST 6 +#define RES4319_LNLDO1_PU 9 +#define RES4319_OTP_PU 10 +#define RES4319_LNLDO2_PU 12 +#define RES4319_XTAL_PU 13 +#define RES4319_ALP_AVAIL 14 +#define RES4319_RX_PWRSW_PU 15 +#define RES4319_TX_PWRSW_PU 16 +#define RES4319_RFPLL_PWRSW_PU 17 +#define RES4319_LOGEN_PWRSW_PU 18 +#define RES4319_AFE_PWRSW_PU 19 +#define RES4319_BBPLL_PWRSW_PU 20 +#define RES4319_HT_AVAIL 21 + +#define CST4319_SPI_CPULESSUSB 0x00000001 +#define CST4319_SPI_CLK_POL 0x00000002 +#define CST4319_SPI_CLK_PH 0x00000008 +#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 +#define CST4319_SPROM_OTP_SEL_SHIFT 6 +#define CST4319_DEFCIS_SEL 0x00000000 +#define CST4319_SPROM_SEL 0x00000040 +#define CST4319_OTP_SEL 0x00000080 +#define CST4319_OTP_PWRDN 0x000000c0 +#define CST4319_SDIO_USB_MODE 0x00000100 +#define CST4319_REMAP_SEL_MASK 0x00000600 +#define CST4319_ILPDIV_EN 0x00000800 +#define CST4319_XTAL_PD_POL 0x00001000 +#define CST4319_LPO_SEL 0x00002000 +#define CST4319_RES_INIT_MODE 0x0000c000 +#define CST4319_PALDO_EXTPNP 0x00010000 +#define CST4319_CBUCK_MODE_MASK 0x00060000 +#define CST4319_CBUCK_MODE_BURST 0x00020000 +#define CST4319_CBUCK_MODE_LPBURST 0x00060000 +#define CST4319_RCAL_VALID 0x01000000 +#define CST4319_RCAL_VALUE_MASK 0x3e000000 +#define CST4319_RCAL_VALUE_SHIFT 25 + +#define PMU1_PLL0_CHIPCTL0 0 +#define PMU1_PLL0_CHIPCTL1 1 +#define PMU1_PLL0_CHIPCTL2 2 +#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 +#define CCTL_4319USB_XTAL_SEL_SHIFT 19 +#define CCTL_4319USB_48MHZ_PLL_SEL 1 +#define CCTL_4319USB_24MHZ_PLL_SEL 2 + + #define PMU_MAX_TRANSITION_DLY 15000 diff --git a/bcm4329/src/include/sbconfig.h b/bcm4329/src/include/sbconfig.h index edf497c..da18ccb 100644 --- a/bcm4329/src/include/sbconfig.h +++ b/bcm4329/src/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbhnddma.h b/bcm4329/src/include/sbhnddma.h index 2aeee9e..7681395 100644 --- a/bcm4329/src/include/sbhnddma.h +++ b/bcm4329/src/include/sbhnddma.h @@ -2,7 +2,7 @@ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface * This supports the following chips: BCM42xx, 44xx, 47xx . * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbpcmcia.h b/bcm4329/src/include/sbpcmcia.h index 121b1a9..d6d8033 100644 --- a/bcm4329/src/include/sbpcmcia.h +++ b/bcm4329/src/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbsdio.h b/bcm4329/src/include/sbsdio.h index 43ed6b5..75aaf4d 100644 --- a/bcm4329/src/include/sbsdio.h +++ b/bcm4329/src/include/sbsdio.h @@ -4,7 +4,7 @@ * * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbsdpcmdev.h b/bcm4329/src/include/sbsdpcmdev.h index 57e832d..7c7c7e4 100644 --- a/bcm4329/src/include/sbsdpcmdev.h +++ b/bcm4329/src/include/sbsdpcmdev.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific device core support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sbsocram.h b/bcm4329/src/include/sbsocram.h index 170e8f2..5ede0b6 100644 --- a/bcm4329/src/include/sbsocram.h +++ b/bcm4329/src/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sdio.h b/bcm4329/src/include/sdio.h index d20d69c..280cb84 100644 --- a/bcm4329/src/include/sdio.h +++ b/bcm4329/src/include/sdio.h @@ -2,7 +2,7 @@ * SDIO spec header file * Protocol and standard (common) device definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/sdioh.h b/bcm4329/src/include/sdioh.h index 960e30c..8123452 100644 --- a/bcm4329/src/include/sdioh.h +++ b/bcm4329/src/include/sdioh.h @@ -2,7 +2,7 @@ * SDIO Host Controller Spec header file * Register map and definitions for the Standard Host Controller * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdioh.h,v 13.13.18.1.16.2 2009/07/28 17:54:46 Exp $ + * $Id: sdioh.h,v 13.13.18.1.16.3 2009/12/08 22:34:21 Exp $ */ #ifndef _SDIOH_H @@ -64,6 +64,7 @@ #define SD_Capabilities_Reserved 0x044 #define SD_MaxCurCap 0x048 #define SD_MaxCurCap_Reserved 0x04C +#define SD_ADMA_SysAddr 0x58 #define SD_SlotInterruptStatus 0x0FC #define SD_HostControllerVersion 0x0FE @@ -81,6 +82,8 @@ #define CAP_MAXBLOCK_S 16 #define CAP_ADMA2_M BITFIELD_MASK(1) #define CAP_ADMA2_S 19 +#define CAP_ADMA1_M BITFIELD_MASK(1) +#define CAP_ADMA1_S 20 #define CAP_HIGHSPEED_M BITFIELD_MASK(1) #define CAP_HIGHSPEED_S 21 #define CAP_DMA_M BITFIELD_MASK(1) @@ -191,6 +194,8 @@ #define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ #define HOST_DATA_WIDTH_S 1 #define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ +#define HOST_DMA_SEL_S 3 +#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ #define HOST_HI_SPEED_EN_S 2 /* misc defines */ diff --git a/bcm4329/src/include/sdiovar.h b/bcm4329/src/include/sdiovar.h index 3c5d512..0179d4c 100644 --- a/bcm4329/src/include/sdiovar.h +++ b/bcm4329/src/include/sdiovar.h @@ -2,7 +2,7 @@ * Structure used by apps whose drivers access SDIO drivers. * Pulled out separately so dhdu and wlu can both use it. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdiovar.h,v 13.5.14.2.16.1 2008/11/20 00:51:32 Exp $ + * $Id: sdiovar.h,v 13.5.14.2.16.2 2009/12/08 22:34:21 Exp $ */ #ifndef _sdiovar_h_ @@ -48,6 +48,7 @@ typedef struct sdreg { #define SDH_DATA_VAL 0x0010 /* Data */ #define SDH_CTRL_VAL 0x0020 /* Control Regs */ #define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ +#define SDH_DMA_VAL 0x0080 /* DMA */ #define NUM_PREV_TRANSACTIONS 16 diff --git a/bcm4329/src/include/siutils.h b/bcm4329/src/include/siutils.h index 7be09d5..b2a4ae3 100644 --- a/bcm4329/src/include/siutils.h +++ b/bcm4329/src/include/siutils.h @@ -2,7 +2,7 @@ * Misc utility routines for accessing the SOC Interconnects * of Broadcom HNBU chips. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.h,v 13.197.4.2.4.3.8.12 2009/09/22 13:28:16 Exp $ + * $Id: siutils.h,v 13.197.4.2.4.3.8.13 2010/03/10 21:34:34 Exp $ */ @@ -225,6 +225,7 @@ extern void si_pci_up(si_t *sih); extern void si_pcie_war_ovr_disable(si_t *sih); extern void si_pcie_extendL1timer(si_t *sih, bool extend); extern int si_pci_fixcfg(si_t *sih); +void si_pmu_res_4319_swctrl_war(si_t *sih, osl_t *osh, bool enable); diff --git a/bcm4329/src/include/spid.h b/bcm4329/src/include/spid.h new file mode 100644 index 0000000..c740296 --- /dev/null +++ b/bcm4329/src/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/bcm4329/src/include/trxhdr.h b/bcm4329/src/include/trxhdr.h index b79ac35..8f5eed9 100644 --- a/bcm4329/src/include/trxhdr.h +++ b/bcm4329/src/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/typedefs.h b/bcm4329/src/include/typedefs.h index e4daeee..4d9dd76 100644 --- a/bcm4329/src/include/typedefs.h +++ b/bcm4329/src/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/include/wlioctl.h b/bcm4329/src/include/wlioctl.h index 751d5cd..6923555 100644 --- a/bcm4329/src/include/wlioctl.h +++ b/bcm4329/src/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.53 2009/10/27 06:18:20 Exp $ + * $Id: wlioctl.h,v 1.601.4.15.2.14.2.59 2010/02/09 13:23:22 Exp $ */ @@ -186,6 +186,7 @@ typedef struct wl_scan_results { #define WL_SCAN_RESULTS_PARTIAL 1 #define WL_SCAN_RESULTS_PENDING 2 #define WL_SCAN_RESULTS_ABORTED 3 +#define WL_SCAN_RESULTS_NO_MEM 4 #define ESCAN_REQ_VERSION 1 @@ -1598,6 +1599,12 @@ typedef struct wl_obss_scan_arg { #define WL_COEX_40MHZ_INTOLERANT 0x02 #define WL_COEX_WIDTH20 0x04 +typedef struct wl_action_obss_coex_req { + uint8 info; + uint8 num; + uint8 ch_list[1]; +} wl_action_obss_coex_req_t; + #define MAX_RSSI_LEVELS 8 @@ -1613,6 +1620,39 @@ typedef struct wl_rssi_event { +#define WLFEATURE_DISABLE_11N 0x00000001 +#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 +#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 +#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 +#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 +#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 +#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 +#define WLFEATURE_DISABLE_11N_GF 0x00000080 + + + +#include <packed_section_end.h> + + +#include <packed_section_start.h> + + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { + struct ether_addr staAddr; + uint16 ieLen; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { + sta_prbreq_wps_ie_hdr_t hdr; + uint8 ieData[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; + +typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { + uint32 totLen; + uint8 ieDataList[1]; +} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; + + #include <packed_section_end.h> #endif diff --git a/bcm4329/src/shared/aiutils.c b/bcm4329/src/shared/aiutils.c index 1962711..a1d00ec 100644 --- a/bcm4329/src/shared/aiutils.c +++ b/bcm4329/src/shared/aiutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/shared/bcmutils.c b/bcm4329/src/shared/bcmutils.c index 9805ee6..c553d8e 100644 --- a/bcm4329/src/shared/bcmutils.c +++ b/bcm4329/src/shared/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * 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: bcmutils.c,v 1.210.4.5.2.4.6.16 2009/10/28 18:25:42 Exp $ + * $Id: bcmutils.c,v 1.210.4.5.2.4.6.17 2009/11/17 02:20:12 Exp $ */ #include <typedefs.h> @@ -33,6 +33,11 @@ #else #include <stdio.h> #include <string.h> +/* This case for external supplicant use */ +#if defined(BCMEXTSUP) +#include <bcm_osl.h> +#endif + #endif /* BCMDRIVER */ #include <bcmendian.h> #include <bcmdevs.h> diff --git a/bcm4329/src/shared/bcmwifi.c b/bcm4329/src/shared/bcmwifi.c index 641a4fd..803acf8 100644 --- a/bcm4329/src/shared/bcmwifi.c +++ b/bcm4329/src/shared/bcmwifi.c @@ -3,7 +3,7 @@ * Contents are wifi-specific, used by any kernel or app-level * software that might want wifi things as it grows. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/shared/hndpmu.c b/bcm4329/src/shared/hndpmu.c index 25712ac..38d72b3 100644 --- a/bcm4329/src/shared/hndpmu.c +++ b/bcm4329/src/shared/hndpmu.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndpmu.c,v 1.95.2.17.4.11.2.50 2009/10/26 14:45:51 Exp $ + * $Id: hndpmu.c,v 1.95.2.17.4.11.2.58 2010/03/10 21:36:44 Exp $ */ #include <typedefs.h> diff --git a/bcm4329/src/shared/linux_osl.c b/bcm4329/src/shared/linux_osl.c index 9c100a4..c2f5682 100644 --- a/bcm4329/src/shared/linux_osl.c +++ b/bcm4329/src/shared/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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: linux_osl.c,v 1.125.12.3.8.5 2009/10/27 04:43:04 Exp $ + * $Id: linux_osl.c,v 1.125.12.3.8.6 2009/12/09 01:29:03 Exp $ */ @@ -81,7 +81,7 @@ struct osl_info { bcm_mem_link_t *dbgmem_list; }; -static int16 linuxbcmerrormap[] = \ +static int16 linuxbcmerrormap[] = { 0, -EINVAL, -EINVAL, @@ -120,13 +120,16 @@ static int16 linuxbcmerrormap[] = \ -EIO, -ENODEV, -EINVAL, - -EINVAL + -EIO, + -EIO, + -EINVAL, + -EINVAL, -#if BCME_LAST != -38 +#if BCME_LAST != -41 #error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmuitls.h" + for new error code defined in bcmutils.h" #endif }; @@ -148,10 +151,8 @@ osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { osl_t *osh; - gfp_t flags; - flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - osh = kmalloc(sizeof(osl_t), flags); + osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); ASSERT(osh); bzero(osh, sizeof(osl_t)); @@ -192,9 +193,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); @@ -452,8 +453,8 @@ void* osl_malloc(osl_t *osh, uint size) { void *addr; - gfp_t flags; + if (osh) ASSERT(osh->magic == OS_HANDLE_MAGIC); @@ -490,8 +491,8 @@ osl_malloc(osl_t *osh, uint size) } original: #endif - flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - if ((addr = kmalloc(size, flags)) == NULL) { + + if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { if (osh) osh->failed++; return (NULL); @@ -603,10 +604,8 @@ void * osl_pktdup(osl_t *osh, void *skb) { void * p; - gfp_t flags; - flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; - if ((p = skb_clone((struct sk_buff*)skb, flags)) == NULL) + if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) return NULL; diff --git a/bcm4329/src/shared/miniopt.c b/bcm4329/src/shared/miniopt.c index 44199ea..6a184a7 100644 --- a/bcm4329/src/shared/miniopt.c +++ b/bcm4329/src/shared/miniopt.c @@ -1,7 +1,7 @@ /* * Description. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/shared/sbutils.c b/bcm4329/src/shared/sbutils.c index 567e94e..7500f14 100644 --- a/bcm4329/src/shared/sbutils.c +++ b/bcm4329/src/shared/sbutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/shared/siutils.c b/bcm4329/src/shared/siutils.c index df34986..6472a78 100644 --- a/bcm4329/src/shared/siutils.c +++ b/bcm4329/src/shared/siutils.c @@ -2,7 +2,7 @@ * Misc utility routines for accessing chip-specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c,v 1.662.4.4.4.16.4.25 2009/09/22 13:32:03 Exp $ + * $Id: siutils.c,v 1.662.4.4.4.16.4.26 2010/02/01 05:51:56 Exp $ */ #include <typedefs.h> @@ -1036,7 +1036,7 @@ si_sdio_init(si_t *sih) sdpregs = (sdpcmd_regs_t *)si_setcore(sih, SDIOD_CORE_ID, 0); ASSERT(sdpregs); - SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d " \ + SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d " "through SD core %d (%p)\n", sih->buscorerev, idx, sii->curidx, sdpregs)); diff --git a/bcm4329/src/shared/siutils_priv.h b/bcm4329/src/shared/siutils_priv.h index 1ec59aa..e8ad7e5 100644 --- a/bcm4329/src/shared/siutils_priv.h +++ b/bcm4329/src/shared/siutils_priv.h @@ -1,7 +1,7 @@ /* * Include file private to the SOC Interconnect support files. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c index 0f04aab..d67daf3 100644 --- a/bcm4329/src/wl/sys/wl_iw.c +++ b/bcm4329/src/wl/sys/wl_iw.c @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c,v 1.51.4.9.2.6.4.57 2009/10/27 04:43:46 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.84.2.3 2010/03/16 22:09:45 Exp $ */ @@ -48,21 +48,27 @@ typedef const struct si_pub si_t; #include <proto/ethernet.h> #include <dngl_stats.h> #include <dhd.h> -#define WL_ERROR(x) +#define WL_ERROR(x) printf x #define WL_TRACE(x) #define WL_ASSOC(x) #define WL_INFORM(x) #define WL_WSEC(x) -#define WL_TRACE_PMK(x) #include <wl_iw.h> + #include <linux/rtnetlink.h> -#include <linux/mutex.h> #define WL_IW_USE_ISCAN 1 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1 +#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 int ap_mode = 0; +#endif #define WL_IW_IOCTL_CALL(func_call) \ do { \ @@ -70,7 +76,6 @@ typedef const struct si_pub si_t; } while (0) static int g_onoff = G_WLAN_SET_ON; -static struct mutex wl_start_lock; extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen); @@ -113,11 +118,13 @@ extern int dhd_wait_pend8021x(struct net_device *dev); #endif static void *g_scan = NULL; -static uint g_scan_specified_ssid; +static volatile uint g_scan_specified_ssid; +static wlc_ssid_t g_specific_ssid; static wlc_ssid_t g_ssid; -wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; +static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; +static volatile uint g_first_broadcast_scan; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) @@ -134,11 +141,13 @@ wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; #endif #if defined(WL_IW_USE_ISCAN) - -static wlc_ssid_t g_specific_ssid; /* chache specific ssid request */ +static void wl_iw_free_ss_cache(void); +static int wl_iw_run_ss_cache_timer(int kick_off); +int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); #define ISCAN_STATE_IDLE 0 #define ISCAN_STATE_SCANING 1 + #define WLC_IW_ISCAN_MAXLEN 2048 typedef struct iscan_buf { struct iscan_buf * next; @@ -163,7 +172,7 @@ typedef struct iscan_info { char ioctlbuf[WLC_IOCTL_SMLEN]; } iscan_info_t; - +#define COEX_DHCP 1 static void wl_iw_bt_flag_set(struct net_device *dev, bool set); static void wl_iw_bt_release(void); @@ -258,35 +267,35 @@ dev_wlc_ioctl( struct ifreq ifr; wl_ioctl_t ioc; mm_segment_t fs; - int ret = -EINVAL; + int ret = -1; - if (g_onoff == G_WLAN_SET_ON) { - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return ret; + } - strcpy(ifr.ifr_name, dev->name); - ifr.ifr_data = (caddr_t) &ioc; + WL_TRACE(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", + __FUNCTION__, current->pid, cmd, arg, len)); + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; - ret = dev_open(dev); - if (ret) { - WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret)); - return ret; - } + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t) &ioc; + + + dev_open(dev); - fs = get_fs(); - set_fs(get_ds()); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) - ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); + fs = get_fs(); + set_fs(get_ds()); +#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 - set_fs(fs); - } - else { - WL_TRACE(("%s: call after driver stop\n", __FUNCTION__)); - } + ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif + set_fs(fs); + return ret; } @@ -376,7 +385,11 @@ 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)); @@ -384,7 +397,7 @@ dev_wlc_bufvar_set( return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen)); } -#endif +#endif static int @@ -393,9 +406,12 @@ 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; len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf)); @@ -533,9 +549,9 @@ 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; @@ -717,15 +733,14 @@ wl_iw_get_rssi( ) { static int rssi = 0; + static wlc_ssid_t ssid = {0}; int error = 0; - wlc_ssid_t ssid; char *p = extra; static char ssidbuf[SSID_FMT_BUF_LEN]; scb_val_t scb_val; - scb_val.val = 0; + bzero(&scb_val, sizeof(scb_val_t)); - bzero(&ssid, sizeof(ssid)); if (g_onoff == G_WLAN_SET_ON) { error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); rssi = dtoh32(scb_val.val); @@ -735,10 +750,6 @@ wl_iw_get_rssi( ssid.SSID_len = dtoh32(ssid.SSID_len); } - if (!ssid.SSID_len) { - return 0; - } - 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; @@ -769,18 +780,18 @@ wl_iw_send_priv_event( return 0; } -#ifdef WL_IW_USE_THREAD_WL_OFF static int _wl_control_sysioc_thread_wl_off(void *data) { struct wl_ctrl *wl_ctl = (struct wl_ctrl *)data; + wl_iw_t *iw = *(wl_iw_t **)netdev_priv(wl_ctl->dev); DAEMONIZE("wlcontrol_sysioc"); WL_TRACE(("%s Entered\n", __FUNCTION__)); - net_os_wake_lock(wl_ctl->dev); - mutex_lock(&wl_start_lock); + WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_OFF, "sysioc_thread_wl_off"); + WAKE_LOCK(iw->pub, WAKE_LOCK_OFF); while (down_interruptible(&wl_ctl->timer_sem) == 0) { WL_TRACE(("%s Turning off wifi dev\n", __FUNCTION__)); @@ -793,6 +804,17 @@ _wl_control_sysioc_thread_wl_off(void *data) dhd_dev_reset(wl_ctl->dev, 1); +#if defined(WL_IW_USE_ISCAN) + + wl_iw_free_ss_cache(); + wl_iw_run_ss_cache_timer(0); + memset(g_scan, 0, G_SCAN_RESULTS); + + g_ss_cache_ctrl.m_link_down = 1; + g_scan_specified_ssid = 0; + + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; +#endif #if defined(BCMLXSDMMC) sdioh_stop(NULL); #endif @@ -801,50 +823,17 @@ _wl_control_sysioc_thread_wl_off(void *data) wl_iw_send_priv_event(wl_ctl->dev, "STOP"); - net_os_wake_lock_timeout_enable(wl_ctl->dev); break; } - mutex_unlock(&wl_start_lock); + WL_TRACE(("%s Exited\n", __FUNCTION__)); - net_os_wake_unlock(wl_ctl->dev); + WAKE_UNLOCK(iw->pub, WAKE_LOCK_OFF); + WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_OFF); complete_and_exit(&wl_ctl->sysioc_exited, 0); KILL_PROC(wl_ctl->sysioc_pid, SIGTERM); } -#endif - -int -wl_control_wl_start(struct net_device *dev) -{ - int ret = 0; - - WL_TRACE(("Enter %s \n", __FUNCTION__)); - - mutex_lock(&wl_start_lock); - if (g_onoff == G_WLAN_SET_OFF) { - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); - -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 0); -#endif - - dhd_dev_reset(dev, 0); - -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 1); -#endif - - dhd_dev_init_ioctl(dev); - - g_onoff = G_WLAN_SET_ON; - } - WL_TRACE(("Exited %s \n", __FUNCTION__)); - - mutex_unlock(&wl_start_lock); - return ret; -} -#ifdef WL_IW_USE_THREAD_WL_OFF static void wl_iw_stop_timerfunc(ulong data) { @@ -852,11 +841,10 @@ wl_iw_stop_timerfunc(ulong data) WL_TRACE(("%s\n", __FUNCTION__)); - del_timer_sync(wl_ctl->timer); + del_timer(wl_ctl->timer); up(&wl_ctl->timer_sem); } -#endif static int wl_iw_control_wl_off( @@ -865,18 +853,24 @@ wl_iw_control_wl_off( ) { int ret = 0; -#ifdef WL_IW_USE_THREAD_WL_OFF static struct wl_ctrl ctl; static struct timer_list timer; -#endif + WL_TRACE(("Enter %s\n", __FUNCTION__)); -#ifdef WL_IW_USE_THREAD_WL_OFF +#ifdef SOFTAP + ap_mode = 0; + ap_cfg_running = FALSE; +#endif + + + ctl.timer = &timer; ctl.dev = dev; sema_init(&ctl.timer_sem, 0); init_completion(&ctl.sysioc_exited); + ctl.sysioc_pid = kernel_thread(_wl_control_sysioc_thread_wl_off, &ctl, 0); timer.data = (ulong)&ctl; @@ -884,28 +878,7 @@ wl_iw_control_wl_off( init_timer(&timer); timer.expires = jiffies + 2000 * HZ / 1000; add_timer(&timer); -#else - mutex_lock(&wl_start_lock); - 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 - dhd_dev_reset(dev, 1); - -#if defined(BCMLXSDMMC) - sdioh_stop(NULL); -#endif - - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); - - wl_iw_send_priv_event(dev, "STOP"); - - net_os_wake_lock_timeout_enable(dev); - } - mutex_unlock(&wl_start_lock); -#endif WL_TRACE(("Exited %s\n", __FUNCTION__)); return ret; @@ -921,17 +894,347 @@ wl_iw_control_wl_on( WL_TRACE(("Enter %s \n", __FUNCTION__)); - ret = wl_control_wl_start(dev); + if (g_onoff == G_WLAN_SET_OFF) { + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); + +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 0); +#endif + + dhd_dev_reset(dev, 0); + +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 1); +#endif + + dhd_dev_init_ioctl(dev); + + g_onoff = G_WLAN_SET_ON; + } wl_iw_send_priv_event(dev, "START"); - net_os_wake_lock_timeout_enable(dev); +#ifdef SOFTAP + if (!ap_fw_loaded) { + wl_iw_iscan_set_scan_broadcast_prep(dev, 0); + } +#else + wl_iw_iscan_set_scan_broadcast_prep(dev, 0); +#endif + WL_TRACE(("Exited %s \n", __FUNCTION__)); return ret; } +#ifdef SOFTAP +static struct ap_profile my_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 +int get_parmeter_from_string( + char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); + +#endif + +int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + + + +int hstr_2_buf(const char *txt, u8 *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + int a, b; + + a = hex2num(*txt++); + if (a < 0) + return -1; + b = hex2num(*txt++); + if (b < 0) + return -1; + *buf++ = (a << 4) | b; + } + + return 0; +} + +#ifdef SOFTAP +int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) +{ + char *str_ptr = param_str; + char sub_cmd[16]; + int ret = 0; + + 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; + } + if (strncmp(sub_cmd, "AP_CFG", 6)) { + 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); + + ret |= get_parmeter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN); + + ret |= get_parmeter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5); + + ret |= get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5); + + ret |= get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5); + + return ret; +} +#endif + + + +#ifdef SOFTAP +static int iwpriv_set_ap_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res = 0; + char *extra = NULL; + struct ap_profile *ap_cfg = &my_ap; + + WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", + info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + + if (wrqu->data.length != 0) { + + char *str_ptr; + + if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + kfree(extra); + return -EFAULT; + } + + extra[wrqu->data.length] = 0; + WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra)); + + memset(ap_cfg, 0, sizeof(struct ap_profile)); + + + + str_ptr = extra; + + init_ap_profile_from_string(extra, ap_cfg); + + } else { + + WL_ERROR(("IWPRIV argument len = 0 \n")); + return -1; + } + + + res |= set_ap_cfg(dev, ap_cfg); + kfree(extra); + + return res; +} +#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) +{ + int i, ret = 0; + char mac_buf[256]; + struct maclist *sta_maclist = (struct maclist *)mac_buf; + + char mac_lst[256]; + char *p_mac_str; + + WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \ + iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, \ + extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags)); + + WL_SOFTAP(("extra:%s\n", extra)); + print_buf((u8 *)p_iwrq, 16, 0); + + memset(sta_maclist, 0, sizeof(mac_buf)); + + sta_maclist->count = 8; + + WL_TRACE((" net device:%s, buf_sz:%d\n", dev->name, sizeof(mac_buf))); + 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]; + + 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], + id->octet[3], id->octet[4], id->octet[5]); + + } + + p_iwrq->data.length = strlen(mac_lst); + + WL_TRACE(("u.pointer:%p\n", p_iwrq->data.pointer)); + WL_TRACE(("resulting str:\n%s \n len:%d\n\n", mac_lst, p_iwrq->data.length)); + + if (p_iwrq->data.length) { + if (copy_to_user(p_iwrq->data.pointer, mac_lst, p_iwrq->data.length)) { + WL_ERROR(("%s: Can't copy to user\n", __FUNCTION__)); + return -EFAULT; + } + } + + WL_TRACE(("Exited %s \n", __FUNCTION__)); + return ret; +} +#endif + + +#ifdef SOFTAP +static int iwpriv_set_mac_filters(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + + int i, ret = -1; + char * extra = NULL; + u8 macfilt[8][6]; + int mac_cnt = 0; + char sub_cmd[16]; + + WL_TRACE((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \ + info->flags:%x, u.data:%p, u.len:%d\n", + info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (wrqu->data.length != 0) { + + char *str_ptr; + + if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + kfree(extra); + return -EFAULT; + } + + extra[wrqu->data.length] = 0; + WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra)); + + 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; + } + +#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)); + goto exit_proc; + } + + if (get_parmeter_from_string(&str_ptr, "MAC_CNT=", + PTYPE_INTDEC, &mac_cnt, 4) != 0) { + WL_ERROR(("ERROR: MAC_CNT param is missing \n")); + goto exit_proc; + } + + if (mac_cnt > MAC_FILT_MAX) { + WL_ERROR(("ERROR: number of MAC filters > MAX\n")); + 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); + } + + + wrqu->data.pointer = NULL; + wrqu->data.length = 0; + ret = 0; + + } else { + + WL_ERROR(("IWPRIV argument len is 0\n")); + return -1; + } + + exit_proc: + kfree(extra); + return ret; +} +#endif #endif @@ -942,8 +1245,10 @@ struct iw_request_info __u16 flags; }; -typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, - void *wrqu, char *extra); +typedef int (*iw_handler)(struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra); #endif static int @@ -970,7 +1275,7 @@ wl_iw_config_commit( bzero(&bssid, sizeof(struct sockaddr)); if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { - WL_ERROR(("Invalid ioctl data.\n")); + WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID)); return error; } @@ -1003,7 +1308,14 @@ wl_iw_set_freq( int error, chan; uint sf = 0; - WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); + WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name)); + +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__)); + return 0; + } +#endif if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { @@ -1515,7 +1827,12 @@ wl_iw_get_aplist( list->buflen = dtoh32(list->buflen); list->version = dtoh32(list->version); list->count = dtoh32(list->count); - ASSERT(list->version == WL_BSS_INFO_VERSION); + if (list->version != WL_BSS_INFO_VERSION) { + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + __FUNCTION__, list->version)); + kfree(list); + return -EINVAL; + } 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; @@ -1585,7 +1902,11 @@ wl_iw_iscan_get_aplist( while (buf) { list = &((wl_iscan_results_t*)buf->iscan_buf)->results; - ASSERT(list->version == WL_BSS_INFO_VERSION); + if (list->version != WL_BSS_INFO_VERSION) { + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + __FUNCTION__, list->version)); + return -EINVAL; + } bi = NULL; for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { @@ -1723,8 +2044,11 @@ wl_iw_iscan_get(iscan_info_t *iscan) } else { buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); - if (!buf) - return WL_SCAN_RESULTS_ABORTED; + if (!buf) { + WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \ + __FUNCTION__)); + return WL_SCAN_RESULTS_NO_MEM; + } buf->next = NULL; if (!iscan->list_hdr) iscan->list_hdr = buf; @@ -1764,31 +2088,30 @@ wl_iw_iscan_get(iscan_info_t *iscan) static void wl_iw_force_specific_scan(iscan_info_t *iscan) { - WL_TRACE(("### Force Specific SCAN for %s\n", g_specific_ssid.SSID)); + WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID)); #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 union iwreq_data wrqu; - char extra[IW_CUSTOM_MAX + 1]; memset(&wrqu, 0, sizeof(wrqu)); - memset(extra, 0, sizeof(extra)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)) - wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, extra); -#else + + wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); -#endif - WL_TRACE(("Send Event SCAN complete\n")); -#endif + 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) @@ -1796,17 +2119,21 @@ _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; + } +#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)) @@ -1816,9 +2143,8 @@ _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 sttaus=%d\n", __FUNCTION__, status)); + if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) { + WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status)); wl_iw_send_scan_complete(iscan); iscan_pass_abort = FALSE; status = -1; @@ -1830,12 +2156,12 @@ _iscan_sysioc_thread(void *data) #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; @@ -1846,7 +2172,7 @@ _iscan_sysioc_thread(void *data) break; case WL_SCAN_RESULTS_PENDING: WL_TRACE(("iscanresults pending\n")); - + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); iscan->timer_on = 1; break; @@ -1860,35 +2186,51 @@ _iscan_sysioc_thread(void *data) wl_iw_force_specific_scan(iscan); } break; + case WL_SCAN_RESULTS_NO_MEM: + WL_TRACE(("iscanresults can't alloc memory: skip\n")); + iscan->iscan_state = ISCAN_STATE_IDLE; + break; default: WL_TRACE(("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 +static void +wl_iw_set_ss_cache_timer_flag(void) +{ + g_ss_cache_ctrl.m_timer_expired = 1; + WL_TRACE(("%s called\n", __FUNCTION__)); +} -void +static int wl_iw_init_ss_cache_ctrl(void) { + WL_TRACE(("%s :\n", __FUNCTION__)); g_ss_cache_ctrl.m_prev_scan_mode = 0; g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; g_ss_cache_ctrl.m_cache_head = NULL; g_ss_cache_ctrl.m_link_down = 0; g_ss_cache_ctrl.m_timer_expired = 0; - g_ss_cache_ctrl.m_timer = NULL; memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN); + + g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!g_ss_cache_ctrl.m_timer) { + return -ENOMEM; + } + g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag; + init_timer(g_ss_cache_ctrl.m_timer); + + return 0; } @@ -1913,12 +2255,6 @@ wl_iw_free_ss_cache(void) *spec_scan_head = NULL; } -static void -wl_iw_set_ss_cache_timer_flag(void) -{ - g_ss_cache_ctrl.m_timer_expired = 1; - WL_TRACE(("%s called\n", __FUNCTION__)); -} static int @@ -1928,24 +2264,15 @@ wl_iw_run_ss_cache_timer(int kick_off) timer = &g_ss_cache_ctrl.m_timer; - if (kick_off) { - *timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); - if (!(*timer)) { - return -ENOMEM; - } - (*timer)->function = (void *)wl_iw_set_ss_cache_timer_flag; - init_timer(*timer); - (*timer)->expires = jiffies + 30000 * HZ / 1000; - add_timer(*timer); - WL_TRACE(("%s : timer starts \n", __FUNCTION__)); - } - else { - if (*timer) { + if (*timer) { + if (kick_off) { + (*timer)->expires = jiffies + 30000 * HZ / 1000; + add_timer(*timer); + WL_TRACE(("%s : timer starts \n", __FUNCTION__)); + } else { del_timer_sync(*timer); - kfree(*timer); - *timer = NULL; + WL_TRACE(("%s : timer stops \n", __FUNCTION__)); } - WL_TRACE(("%s : timer stops \n", __FUNCTION__)); } return 0; @@ -1955,8 +2282,12 @@ wl_iw_run_ss_cache_timer(int kick_off) void wl_iw_release_ss_cache_ctrl(void) { + WL_TRACE(("%s :\n", __FUNCTION__)); wl_iw_free_ss_cache(); wl_iw_run_ss_cache_timer(0); + if (g_ss_cache_ctrl.m_timer) { + kfree(g_ss_cache_ctrl.m_timer); + } } @@ -2020,7 +2351,7 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; - WL_TRACE(("%s : %dth SSID %s\n", __FUNCTION__, i, bi->SSID)); + WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID)); for (;node;) { if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { @@ -2074,12 +2405,13 @@ __u16 *merged_len) node = g_ss_cache_ctrl.m_cache_head; for (;node;) { list_merge = (wl_scan_results_t *)node; - WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); + WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count)); if (buflen_from_user - *merged_len > 0) { *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info, extra + *merged_len, buflen_from_user - *merged_len); } else { + WL_TRACE(("%s: exit with break\n", __FUNCTION__)); break; } node = node->next; @@ -2131,7 +2463,16 @@ wl_iw_set_scan( char *extra ) { - WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); + int error; + WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); + +#if defined(SOFTAP) + + if (ap_cfg_running) { + WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + return 0; + } +#endif if (g_onoff == G_WLAN_SET_OFF) @@ -2139,28 +2480,98 @@ wl_iw_set_scan( memset(&g_specific_ssid, 0, sizeof(g_specific_ssid)); - g_scan_specified_ssid = 0; +#ifndef WL_IW_USE_ISCAN + + g_scan_specified_ssid = 0; +#endif #if WIRELESS_EXT > 17 if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; - g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID), req->essid_len); - memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len); - g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len); - g_scan_specified_ssid = 1; - WL_TRACE(("Specific scan ssid=%s len=%d\n", g_specific_ssid.SSID, g_specific_ssid.SSID_len)); + 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)); + return -EBUSY; + } + if (g_scan_specified_ssid) { + WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n", \ + __FUNCTION__, req->essid)); + + return -EBUSY; + } + else { + g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID), \ + req->essid_len); + memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len); + g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len); + g_scan_specified_ssid = 1; + WL_TRACE(("### Specific scan ssid=%s len=%d\n", \ + g_specific_ssid.SSID, g_specific_ssid.SSID_len)); + } } } -#endif +#endif - (void) dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)); + 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; + } return 0; } #ifdef WL_IW_USE_ISCAN +int +wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) +{ + wlc_ssid_t ssid; + iscan_info_t *iscan = g_iscan; + + + 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__)); + } + else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) { + WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); + return 0; + } + + + memset(&ssid, 0, sizeof(ssid)); + + iscan->list_cur = iscan->list_hdr; + iscan->iscan_state = ISCAN_STATE_SCANING; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + if (flag) + rtnl_lock(); +#endif + + dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag)); + wl_iw_set_event_mask(dev); + + WL_TRACE(("+++: Set Broadcast ISCAN\n")); + + wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + if (flag) + rtnl_unlock(); +#endif + + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); + + iscan->timer_on = 1; + + return 0; +} static int wl_iw_iscan_set_scan( struct net_device *dev, @@ -2172,48 +2583,68 @@ wl_iw_iscan_set_scan( wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; - WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); + WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); - if (g_onoff == G_WLAN_SET_OFF) +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); return 0; + } +#endif + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return 0; + } 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); } - if (iscan->iscan_state == ISCAN_STATE_SCANING) { - return 0; + + if (g_scan_specified_ssid) { + WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \ + __FUNCTION__)); + return EBUSY; } memset(&ssid, 0, sizeof(ssid)); - g_scan_specified_ssid = 0; #if WIRELESS_EXT > 17 if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { int as = 0; struct iw_scan_req *req = (struct iw_scan_req *)extra; + 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; + } 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); - g_scan_specified_ssid = 1; - (void) dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as)); + 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); } + else { + g_scan_specified_ssid = 0; + + if (iscan->iscan_state == ISCAN_STATE_SCANING) { + WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__)); + return 0; + } + } } #endif - iscan->list_cur = iscan->list_hdr; - iscan->iscan_state = ISCAN_STATE_SCANING; - (void) dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, - &iscan->scan_flag, sizeof(iscan->scan_flag)); - wl_iw_set_event_mask(dev); - wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); - mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); - iscan->timer_on = 1; + wl_iw_iscan_set_scan_broadcast_prep(dev, 0); return 0; } @@ -2337,10 +2768,16 @@ wl_iw_get_scan_prep( for (i = 0; i < list->count && i < IW_MAX_AP; i++) { - ASSERT(list->version == WL_BSS_INFO_VERSION); + if (list->version != WL_BSS_INFO_VERSION) { + 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; @@ -2391,13 +2828,14 @@ wl_iw_get_scan_prep( if (bi->rateset.count) { - if (((event - extra) + IW_EV_LCP_LEN) <= (int)end) { + 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); } @@ -2433,7 +2871,8 @@ wl_iw_get_scan( #if defined(WL_IW_USE_ISCAN) iscan_info_t *iscan = g_iscan; iscan_buf_t * p_buf; -#endif + uint32 counter = 0; +#endif WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user)); @@ -2474,6 +2913,7 @@ wl_iw_get_scan( list = kmalloc(len, GFP_KERNEL); if (!list) { WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name)); + g_scan_specified_ssid = 0; return -ENOMEM; } } @@ -2481,7 +2921,7 @@ 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 too big %d\n", dev->name, __FUNCTION__, len)); + WL_TRACE(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, len)); dwrq->length = len; if (g_scan_specified_ssid) kfree(list); @@ -2491,11 +2931,14 @@ wl_iw_get_scan( 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)); - if (g_scan_specified_ssid) + 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); + } return -EINVAL; } @@ -2506,20 +2949,24 @@ wl_iw_get_scan( } #if defined(WL_IW_USE_ISCAN) + if (g_scan_specified_ssid) + WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count)); p_buf = iscan->list_hdr; while (p_buf != iscan->list_cur) { list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count)); + 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 +#endif if (g_ss_cache_ctrl.m_link_down) { wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); @@ -2530,7 +2977,10 @@ wl_iw_get_scan( wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); - +#if defined(WL_IW_USE_ISCAN) + + g_scan_specified_ssid = 0; +#endif if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user) len = len_ret; @@ -2563,16 +3013,28 @@ wl_iw_iscan_get_scan( __u16 merged_len = 0; uint buflen_from_user = dwrq->length; - WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length)); +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + return -EINVAL; + } +#endif + if (!extra) { - WL_TRACE(("%s: SIOCGIWSCAN GET bad parameter\n", dev->name)); + WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name)); return -EINVAL; } + 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; + } if ((!iscan) || (iscan->sysioc_pid < 0)) { + WL_TRACE(("%ssysioc_pid\n", __FUNCTION__)); return wl_iw_get_scan(dev, info, dwrq, extra); } @@ -2606,11 +3068,12 @@ 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(("list->version %d != WL_BSS_INFO_VERSION\n", list->version)); - return -EINVAL; /* if WL_BSS_INFO_VERSION is corrupted iscan results are garbage */ + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \ + __FUNCTION__, list->version)); + return -EINVAL; } bi = NULL; @@ -2700,9 +3163,15 @@ wl_iw_iscan_get_scan( dwrq->length += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); + + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); + + if (!dwrq->length) + return -EAGAIN; + return 0; } #endif @@ -2722,6 +3191,8 @@ wl_iw_set_essid( memset(&g_ssid, 0, sizeof(g_ssid)); + CHECK_EXTRA_FOR_NULL(extra); + if (dwrq->length && extra) { #if WIRELESS_EXT > 20 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length); @@ -2737,6 +3208,7 @@ wl_iw_set_essid( if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &g_ssid, sizeof(g_ssid)))) return error; + WL_TRACE(("%s: join SSID=%s\n", __FUNCTION__, g_ssid.SSID)); return 0; } @@ -3358,6 +3830,11 @@ wl_iw_set_wpaie( char *extra ) { + + WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name)); + + CHECK_EXTRA_FOR_NULL(extra); + dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); return 0; @@ -3391,6 +3868,8 @@ wl_iw_set_encodeext( WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); + CHECK_EXTRA_FOR_NULL(extra); + memset(&key, 0, sizeof(key)); iwe = (struct iw_encode_ext *)extra; @@ -3506,12 +3985,15 @@ wl_iw_set_pmksa( int ret = 0; char eabuf[ETHER_ADDR_STR_LEN]; - WL_TRACE_PMK(("%s: SIOCSIWPMKSA\n", dev->name)); + WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name)); + + CHECK_EXTRA_FOR_NULL(extra); + iwpmksa = (struct iw_pmksa *)extra; bzero((char *)eabuf, ETHER_ADDR_STR_LEN); if (iwpmksa->cmd == IW_PMKSA_FLUSH) { - WL_TRACE_PMK(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); + WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); bzero((char *)&pmkid_list, sizeof(pmkid_list)); } @@ -3521,15 +4003,16 @@ 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_TRACE_PMK(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", + WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, eabuf))); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_TRACE_PMK(("%02x ", pmkidptr->pmkid[0].PMKID[j])); - WL_TRACE_PMK(("\n")); + WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j])); + WL_WSEC(("\n")); } for (i = 0; i < pmkid_list.pmkids.npmkid; i++) @@ -3569,33 +4052,33 @@ wl_iw_set_pmksa( } else ret = -EINVAL; - { uint j; uint k; k = pmkid_list.pmkids.npmkid; - WL_TRACE_PMK(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", + WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID, eabuf))); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_TRACE_PMK(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j])); - WL_TRACE_PMK(("\n")); + WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j])); + WL_WSEC(("\n")); } } - WL_TRACE_PMK(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret)); + WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid)); for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { uint j; - WL_TRACE_PMK(("PMKID[%d]: %s = ", i, + WL_WSEC(("PMKID[%d]: %s = ", i, bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID, eabuf))); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_TRACE_PMK(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j])); - WL_TRACE_PMK(("\n")); + WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j])); + WL_WSEC(("\n")); } - WL_TRACE_PMK(("\n")); + 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 @@ -3629,6 +4112,13 @@ wl_iw_set_wpaauth( WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + return 0; + } +#endif + paramid = vwrq->flags & IW_AUTH_INDEX; paramval = vwrq->value; @@ -3869,9 +4359,901 @@ wl_iw_get_wpaauth( #endif +#ifdef SOFTAP +static int ap_macmode = MACLIST_MODE_DISABLED; +static struct mflist ap_black_list; static int -wl_iw_set_priv( +wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key) +{ + char hex[] = "XX"; + unsigned char *data = key->data; + + switch (strlen(keystr)) { + case 5: + case 13: + case 16: + key->len = strlen(keystr); + memcpy(data, keystr, key->len + 1); + break; + case 12: + case 28: + case 34: + case 66: + + if (!strnicmp(keystr, "0x", 2)) + keystr += 2; + else + return -1; + + case 10: + case 26: + case 32: + case 64: + key->len = strlen(keystr) / 2; + while (*keystr) { + strncpy(hex, keystr, 2); + *data++ = (char) bcm_strtoul(hex, NULL, 16); + keystr += 2; + } + break; + default: + return -1; + } + + switch (key->len) { + case 5: + key->algo = CRYPTO_ALGO_WEP1; + break; + case 13: + key->algo = CRYPTO_ALGO_WEP128; + break; + case 16: + + key->algo = CRYPTO_ALGO_AES_CCM; + break; + case 32: + key->algo = CRYPTO_ALGO_TKIP; + break; + default: + return -1; + } + + + key->flags |= WL_PRIMARY_KEY; + + return 0; +} + +#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); + +#else + +#define SHA1HashSize 20 +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; +} + +#endif + +int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val) +{ + struct { + int cfg; + int val; + } bss_setbuf; + + int bss_set_res; + char smbuf[WLC_IOCTL_SMLEN]; + memset(smbuf, 0, sizeof(smbuf)); + + bss_setbuf.cfg = 1; + bss_setbuf.val = val; + + bss_set_res = dev_iw_iovar_setbuf(dev, "bss", + &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf)); + WL_TRACE(("\n:%s: bss_set_result:%d\n", __FUNCTION__, bss_set_res)); + + return bss_set_res; +} + +static int wl_bssiovar_mkbuf( + const char *iovar, + int bssidx, + void *param, + int paramlen, + void *bufptr, + int buflen, + int *perr) +{ + const char *prefix = "bsscfg:"; + int8* p; + uint prefixlen; + uint namelen; + uint iolen; + + 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; + + + 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); + + *perr = 0; + return iolen; +} + + + + +int get_user_params(char *user_params, struct iw_point *dwrq) +{ + int ret = 0; + + if (copy_from_user(user_params, dwrq->pointer, dwrq->length)) { + WL_ERROR(("\n%s: no user params: uptr:%p, ulen:%d\n", + __FUNCTION__, dwrq->pointer, dwrq->length)); + return -EFAULT; + } + + WL_TRACE(("\n%s: iwpriv user params:%s\n", __FUNCTION__, user_params)); + + return ret; +} + + +#ifdef SOFTAP + +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 thr_wait_for_2nd_eth_dev(void *data) +{ + + DAEMONIZE("wl0_eth_wthread"); + + WL_TRACE(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid)); + + if (down_timeout(&ap_eth_sema, msecs_to_jiffies(5000)) != 0) { + WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__)); + return -1; + } + + if (!ap_net_dev) { + WL_ERROR((" ap_net_dev is null !!!")); + return -1; + } + + WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n", + __FUNCTION__, ap_net_dev->name)); + + ap_mode = 1; + ap_cfg_running = TRUE; + + bcm_mdelay(500); + + + wl_iw_send_priv_event(priv_dev, "ASCII_CMD=AP_BSS_START"); + + WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); + + return 0; +} + + +static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap) +{ + int updown = 0; + int channel = 0; + + wlc_ssid_t ap_ssid; + wlc_ssid_t null_ssid; + int max_assoc = 8; + int mpc = 0; + + int res = 0; + int apsta_var = 0; + int iolen = 0; + int mkvar_err = 0; + int bsscfg_index = 1; + char buf[WLC_IOCTL_SMLEN]; + + ap_mode = 0; + + memset(&null_ssid, 0, sizeof(wlc_ssid_t)); + WL_SOFTAP(("wl_iw: set ap profile:\n")); + WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); + WL_SOFTAP((" security = '%s'\n", ap->sec)); + if (ap->key[0] != '\0') + WL_SOFTAP((" key = '%s'\n", ap->key)); + WL_SOFTAP((" channel = %d\n", ap->channel)); + WL_SOFTAP((" max scb = %d\n", ap->max_scb)); + + + if (!ap_cfg_running) { + + + sema_init(&ap_eth_sema, 0); + + mpc = 0; + res |= dev_wlc_intvar_set(dev, "mpc", mpc); + + updown = 0; + res |= dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)); + + +#ifdef AP_ONLY + + apsta_var = 0; + res | = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)); + + apsta_var = 1; + res |= dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)); + 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, + buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen); + WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); +#endif + + updown = 1; + res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); + WL_TRACE(("\n:%s >>>> dev_wlc_ioctl(WLC_UP) updown:%d, \n", __FUNCTION__, updown)); + + } else { + + res |= dev_iw_write_cfg1_bss_var(dev, 0); + } + + + if (ap->channel == 0) { + int chosen = 0; + wl_uint32_list_t request; + int rescan = 0; + int retry = 0; + int ret = 0; + res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); + res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid)); + + auto_channel_retry: + request.count = htod32(0); + ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request)); + if (ret < 0) { + WL_ERROR(("can't start auto channel scan\n")); + return -1; + } + + get_channel_retry: + bcm_mdelay(500); + + ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); + if (ret < 0 || dtoh32(chosen) == 0) { + if (retry++ < 3) + goto get_channel_retry; + else { + WL_ERROR(("can't get auto channel sel, err = %d, \ + chosen = %d\n", ret, chosen)); + return -1; + } + } + if ((chosen == 1) && (!rescan++)) + goto auto_channel_retry; + WL_SOFTAP(("Set auto channel = %d\n", chosen)); + ap->channel = chosen; + dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)); + } + + channel = ap->channel; + res |= dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)); + + if (!ap_cfg_running) { + updown = 0; + res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); + } + + max_assoc = ap->max_scb; + res |= dev_wlc_intvar_set(dev, "maxassoc", max_assoc); + + ap_ssid.SSID_len = strlen(ap->ssid); + strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); + + + iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid), + ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen); + + if (!ap_cfg_running) { + + kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0); + } else { + + + + WL_TRACE(("%s: Configure security & restart AP bss \n", __FUNCTION__)); + + + res |= wl_iw_set_ap_security(dev, &my_ap); + + + res |= dev_iw_write_cfg1_bss_var(dev, 1); + } + + return res; +} +#endif + + + +static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap) +{ + int wsec = 0; + int wpa_auth = 0; + int res = 0; + int i; + char *ptr; + + WL_SOFTAP(("\nsetting SOFTAP security mode:\n")); + WL_SOFTAP(("wl_iw: set ap profile:\n")); + WL_SOFTAP((" ssid = '%s'\n", ap->ssid)); + WL_SOFTAP((" security = '%s'\n", ap->sec)); + if (ap->key[0] != '\0') + WL_SOFTAP((" key = '%s'\n", ap->key)); + 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; + res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); + + WL_SOFTAP(("=====================\n")); + WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res)); + WL_SOFTAP(("=====================\n")); + + } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { + + + wl_wsec_key_t key; + memset(&key, 0, sizeof(key)); + + wsec = WEP_ENABLED; + res = dev_wlc_intvar_set(dev, "wsec", wsec); + + key.index = 0; + if (wl_iw_parse_wep(ap->key, &key)) { + WL_SOFTAP(("wep key parse err!\n")); + return -1; + } + + key.index = htod32(key.index); + key.len = htod32(key.len); + key.algo = htod32(key.algo); + key.flags = htod32(key.flags); + + res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + + wpa_auth = WPA_AUTH_DISABLED; + res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); + + WL_SOFTAP(("=====================\n")); + WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res)); + WL_SOFTAP(("=====================\n")); + + } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) { + + + + wsec_pmk_t psk; + size_t key_len; + + wsec = AES_ENABLED; + dev_wlc_intvar_set(dev, "wsec", wsec); + + key_len = strlen(ap->key); + if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { + WL_SOFTAP(("passphrase must be between %d and %d characters long\n", + WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); + 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]); + ptr += 8; + } + 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); + } else { + psk.key_len = htod16((ushort) key_len); + memcpy(psk.key, ap->key, key_len); + } + psk.flags = htod16(WSEC_PASSPHRASE); + dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); + + wpa_auth = WPA2_AUTH_PSK; + dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); + + } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) { + + + wsec_pmk_t psk; + size_t key_len; + + wsec = TKIP_ENABLED; + res = dev_wlc_intvar_set(dev, "wsec", wsec); + + key_len = strlen(ap->key); + if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) { + WL_SOFTAP(("passphrase must be between %d and %d characters long\n", + WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN)); + 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]); + ptr += 8; + } + printk("%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); + } else { + psk.key_len = htod16((ushort) key_len); + memcpy(psk.key, ap->key, key_len); + } + + psk.flags = htod16(WSEC_PASSPHRASE); + res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk)); + + wpa_auth = WPA_AUTH_PSK; + res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth); + + WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res)); + } + + return res; +} + + + +int get_parmeter_from_string( + char **str_ptr, const char *token, + int param_type, void *dst, int param_max_len) +{ + char int_str[7] = "0"; + int parm_str_len; + char *param_str_begin; + char *param_str_end; + char *orig_str = *str_ptr; + + if (!strncmp(*str_ptr, token, strlen(token))) { + + strsep(str_ptr, "=,"); + param_str_begin = *str_ptr; + strsep(str_ptr, "=,"); + + if (*str_ptr == NULL) { + + parm_str_len = strlen(param_str_begin); + } else { + 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_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n", + parm_str_len, param_max_len)); + + parm_str_len = param_max_len; + } + + 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); + + memcpy(int_str, param_str_begin, parm_str_len); + + *pdst_int = simple_strtoul(int_str, &eptr, 10); + + 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); + } + break; + 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; + } else { + WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n", + __FUNCTION__, token, orig_str)); + + return -1; + } +} + + +static int iwpriv_softap_stop(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res; + + WL_SOFTAP((" iw_handler SOFTAP_STP \n")); + + + ap_mode = 0; + ap_cfg_running = FALSE; + + + res = dev_iw_write_cfg1_bss_var(dev, 2); + + wrqu->data.length = 0; + + return res; +} + + + +static int iwpriv_fw_reload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + + int ret = -1; + char extra[256]; + char *fwstr = fw_path ; + + WL_SOFTAP(("current firmware_path[]=%s\n", fwstr)); + + WL_TRACE((">Got FW_RELOAD cmd:" + "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, \ + fw_path:%p, len:%d \n", + 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; + + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + ret = -EFAULT; + goto exit_proc; + } + + + extra[wrqu->data.length] = 8; + str_ptr = extra; + + if (get_parmeter_from_string(&str_ptr, "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) { + WL_ERROR(("Error: extracting FW_PATH='' string\n")); + goto exit_proc; + } + + 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; + } + + WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr)); + ret = 0; + } else { + WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length)); + } + +exit_proc: + return ret; +} +#ifdef SOFTAP +static int iwpriv_wpasupp_loop_tst(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res = 0; + char *params = NULL; + + WL_TRACE((">Got IWPRIV wp_supp loopback cmd test:" + "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n", + info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (wrqu->data.length != 0) { + + 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; + } + + params[wrqu->data.length] = 0; + WL_SOFTAP(("\n>> copied from user:\n %s\n", params)); + } else { + WL_ERROR(("ERROR param length is 0\n")); + return -EFAULT; + } + + + res = wl_iw_send_priv_event(dev, params); + kfree(params); + + return res; +} +#endif + + +static int + iwpriv_en_ap_bss( + struct net_device *dev, + struct iw_request_info *info, + void *wrqu, + char *extra) +{ + int res = 0; + WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); + + + if (wl_iw_set_ap_security(dev, &my_ap) != 0) { + WL_ERROR(("!!!!:ERROR setting SOFTAP security in :%s\n", __FUNCTION__)); + }; + + + dev_iw_write_cfg1_bss_var(dev, 1); + 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)); + + dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len); + + return 0; +} + + +static int +set_ap_mac_list(struct net_device *dev, char *buf) +{ + struct mac_list_set *mac_list_set = (struct mac_list_set *)buf; + struct maclist *white_maclist = (struct maclist *)&mac_list_set->white_list; + struct maclist *black_maclist = (struct maclist *)&mac_list_set->black_list; + int mac_mode = mac_list_set->mode; + int length; + int i; + + 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; + char mac_buf[256] = {0}; + 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], \ + 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], \ + 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], \ + ETHER_ADDR_LEN)) { + WL_SOFTAP(("match allow, let it be\n")); + break; + } + } + 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, \ + WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, + sizeof(scb_val_t)); + } + } + } + } + return 0; +} +#endif + + +#ifdef SOFTAP +int set_macfilt_from_string(struct mflist *pmflist, char **param_str) +{ + return 0; +} +#endif + + +#ifdef SOFTAP +#define PARAM_OFFSET PROFILE_OFFSET + +int wl_iw_process_private_ascii_cmd( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *dwrq, + char *cmd_str) +{ + int ret = 0; + char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD="); + + WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n", + __FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET)); + + if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) { + + WL_SOFTAP((" AP_CFG \n")); + + ap_mode = 0; + + + if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) { + WL_ERROR(("ERROR: SoftAP CFG prams !\n")); + ret = -1; + } else { + set_ap_cfg(dev, &my_ap); + } + + } else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) { + + WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n")); + + + WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name)); + + if (ap_net_dev == NULL) { + printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n"); + } else { + + iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str); + } + + } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) { + + + + } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) { + + WL_SOFTAP((" \n temp DOWN SOFTAP\n")); + ret = dev_iw_write_cfg1_bss_var(dev, 0); + } + + return ret; + +} +#endif +static int wl_iw_set_priv( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, @@ -3881,6 +5263,7 @@ 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; @@ -3889,34 +5272,38 @@ wl_iw_set_priv( return -EFAULT; } - WL_TRACE(("%s: SIOCSIWPRIV requst = %s\n", - dev->name, extra)); + 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) { - if (strnicmp(extra, "START", strlen("START")) == 0) { - wl_iw_control_wl_on(dev, info); - WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); - } + WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_PRIV, "wl_iw_set_priv"); + WAKE_LOCK(iw->pub, WAKE_LOCK_PRIV); if (g_onoff == G_WLAN_SET_OFF) { - WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__)); - kfree(extra); - net_os_wake_unlock(dev); - return -EFAULT; + 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__)); + } } if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS - WL_TRACE(("%s: active scan setting supppressed\n", dev->name)); + 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) #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS - WL_TRACE(("%s: passive scan setting supppressed\n", dev->name)); + 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 @@ -3932,15 +5319,25 @@ wl_iw_set_priv( ret = wl_iw_control_wl_off(dev, info); else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(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) { + WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n")); + set_ap_mac_list(dev, (extra + PROFILE_OFFSET)); + } +#endif else { snprintf(extra, MAX_WX_STRING, "OK"); dwrq->length = strlen("OK") + 1; - WL_TRACE(("Unkown PRIVATE command , ignored\n")); + 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)) { kfree(extra); @@ -4051,11 +5448,41 @@ static const iw_handler wl_iw_priv_handler[] = { NULL, (iw_handler)wl_iw_control_wl_off, NULL, - (iw_handler)wl_iw_control_wl_on + (iw_handler)wl_iw_control_wl_on, +#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 }; -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, @@ -4096,8 +5523,60 @@ static const struct iw_priv_args wl_iw_priv_args[] = { 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, "START" - } -}; + }, + +#ifdef SOFTAP + + + { + WL_SET_AP_CFG, + IW_PRIV_TYPE_CHAR | 256, + 0, + "AP_SET_CFG" + }, + + { + WL_AP_STA_LIST, + 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, + "AP_SET_MAC_FLTR" + }, + + { + WL_AP_BSS_START, + 0, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + "AP_BSS_START" + }, + + { + AP_LPB_CMD, + 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, + "AP_BSS_STOP" + }, + { + WL_FW_RELOAD, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0, + "WL_FW_RELOAD" + }, +#endif + }; const struct iw_handler_def wl_iw_handler_def = { @@ -4114,8 +5593,9 @@ const struct iw_handler_def wl_iw_handler_def = }; #endif -int -wl_iw_ioctl( + + +int wl_iw_ioctl( struct net_device *dev, struct ifreq *rq, int cmd @@ -4127,10 +5607,13 @@ 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)); if (cmd < SIOCIWFIRST || IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || - !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) - return -EOPNOTSUPP; + !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) { + WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd)); + return -EOPNOTSUPP; + } switch (cmd) { @@ -4147,11 +5630,12 @@ wl_iw_ioctl( case SIOCSIWENCODEEXT: case SIOCGIWENCODEEXT: #endif - max_tokens = IW_ENCODING_TOKEN_MAX; + max_tokens = wrq->u.data.length; break; case SIOCGIWRANGE: - max_tokens = sizeof(struct iw_range); + + max_tokens = sizeof(struct iw_range) + 500; break; case SIOCGIWAPLIST: @@ -4180,15 +5664,21 @@ wl_iw_ioctl( max_tokens = IW_MAX_SPY; break; +#if WIRELESS_EXT > 17 + case SIOCSIWPMKSA: + case SIOCSIWGENIE: +#endif case SIOCSIWPRIV: max_tokens = wrq->u.data.length; break; } if (max_tokens && wrq->u.data.pointer) { - if (wrq->u.data.length > max_tokens) + 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; - + } if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) return -ENOMEM; @@ -4327,12 +5817,56 @@ 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; 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); + + WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type)); + + switch (event_type) { +#if defined(SOFTAP) + case WLC_E_PRUNE: + if (ap_mode) { + char *macaddr = (char *)&e->addr; + WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n", + macaddr[0], macaddr[1], macaddr[2], macaddr[3], \ + macaddr[4], macaddr[5])); + + + if (ap_macmode) + { + int i; + for (i = 0; i < ap_black_list.count; i++) { + if (!bcmp(macaddr, &ap_black_list.ea[i], \ + sizeof(struct ether_addr))) { + WL_SOFTAP(("mac in black list, ignore it\n")); + break; + } + } + + 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], + macaddr[3], macaddr[4], macaddr[5]); + wl_iw_send_priv_event(priv_dev, mac_buf); + } + } + } + break; +#endif case WLC_E_TXFAIL: cmd = IWEVTXDROP; memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); @@ -4342,12 +5876,26 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) case WLC_E_JOIN: case WLC_E_ASSOC_IND: case WLC_E_REASSOC_IND: +#if defined(SOFTAP) + WL_SOFTAP(("STA connect received %d\n", event_type)); + if (ap_mode) { + wl_iw_send_priv_event(priv_dev, "STA_JOIN"); + return; + } +#endif memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; cmd = IWEVREGISTERED; 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_mode) { + wl_iw_send_priv_event(priv_dev, "STA_LEAVE"); + return; + } +#endif cmd = SIOCGIWAP; bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; @@ -4359,11 +5907,23 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) if (!(flags & WLC_EVENT_MSG_LINK)) { +#ifdef SOFTAP + if (ap_mode && !strncmp(dev->name, "wl0.1", 5)) { + + 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; +#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 { @@ -4371,6 +5931,17 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) g_ss_cache_ctrl.m_link_down = 0; memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN); +#ifdef SOFTAP + + if (ap_mode && !strncmp(dev->name, "wl0.1", 5)) { + + WL_SOFTAP(("AP UP %d\n", event_type)); + wl_iw_send_priv_event(priv_dev, "AP_UP"); + } else { + WL_TRACE(("STA_LINK_UP\n")); + } +#else +#endif WL_TRACE(("Link UP\n")); } @@ -4382,7 +5953,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) wrqu.data.length = datalen + 1; extra[0] = WLC_E_ACTION_FRAME; memcpy(&extra[1], data, datalen); - printf("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length); + WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length)); } break; @@ -4461,7 +6032,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) wrqu.data.length = strlen(extra); WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); #endif - break; + break; default: @@ -4469,14 +6040,8 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; } #ifndef SANDGATE2G - 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); - } + if (cmd) + wireless_send_event(dev, cmd, &wrqu, extra); #endif #if WIRELESS_EXT > 14 @@ -4507,14 +6072,14 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat goto done; phy_noise = dtoh32(phy_noise); - WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise)); + WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise)); scb_val.val = 0; if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) goto done; rssi = dtoh32(scb_val.val); - WL_TRACE(("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi)); + WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi)); if (rssi <= WL_IW_RSSI_NO_SIGNAL) wstats->qual.qual = 0; else if (rssi <= WL_IW_RSSI_VERY_LOW) @@ -4538,13 +6103,13 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat #endif #if WIRELESS_EXT > 11 - WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t))); + WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t))); memset(&cnt, 0, sizeof(wl_cnt_t)); res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); if (res) { - WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res)); + WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res)); goto done; } @@ -4621,19 +6186,17 @@ _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: @@ -4662,15 +6225,12 @@ _bt_dhcp_sysioc_thread(void *data) 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); } @@ -4741,6 +6301,7 @@ 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_iscan->scan_flag = 0; @@ -4755,7 +6316,6 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) if (iscan->sysioc_pid < 0) return -ENOMEM; #endif - mutex_init(&wl_start_lock); iw = *(wl_iw_t **)netdev_priv(dev); iw->pub = (dhd_pub_t *)dhdp; @@ -4769,10 +6329,16 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) memset(g_scan, 0, G_SCAN_RESULTS); g_scan_specified_ssid = 0; + wl_iw_init_ss_cache_ctrl(); wl_iw_bt_init(dev); +#ifdef SOFTAP + priv_dev = dev; +#endif + + return 0; } @@ -4805,5 +6371,12 @@ void wl_iw_detach(void) wl_iw_release_ss_cache_ctrl(); wl_iw_bt_release(); +#ifdef SOFTAP + if (ap_mode) { + WL_TRACE(("\n%s AP is going down\n", __FUNCTION__)); + + wl_iw_send_priv_event(priv_dev, "AP_DOWN"); + } +#endif } diff --git a/bcm4329/src/wl/sys/wl_iw.h b/bcm4329/src/wl/sys/wl_iw.h index 0321964..7f770fd 100644 --- a/bcm4329/src/wl/sys/wl_iw.h +++ b/bcm4329/src/wl/sys/wl_iw.h @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2010, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -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.9 2009/10/14 04:27:31 Exp $ + * $Id: wl_iw.h,v 1.5.34.1.6.13.2.2 2010/03/16 22:09:45 Exp $ */ @@ -35,6 +35,9 @@ #include <wlioctl.h> + + + #define WL_IW_RSSI_MINVAL -200 #define WL_IW_RSSI_NO_SIGNAL -91 #define WL_IW_RSSI_VERY_LOW -80 @@ -53,11 +56,26 @@ #define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) #define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) + +#define WL_SET_AP_CFG (SIOCIWFIRSTPRIV+15) +#define WL_AP_STA_LIST (SIOCIWFIRSTPRIV+17) +#define WL_AP_MAC_FLTR (SIOCIWFIRSTPRIV+19) +#define WL_AP_BSS_START (SIOCIWFIRSTPRIV+21) +#define AP_LPB_CMD (SIOCIWFIRSTPRIV+23) +#define WL_AP_STOP (SIOCIWFIRSTPRIV+25) +#define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27) +#define WL_AP_SPARE2 (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 CHECK_EXTRA_FOR_NULL(extra) \ +if (!extra) { \ + WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \ + return -EINVAL; \ +} typedef struct wl_iw { char nickname[IW_ESSID_MAX_SIZE]; @@ -106,8 +124,41 @@ typedef struct wl_iw_ss_cache_ctrl { uint m_cons_br_scan_cnt; struct timer_list *m_timer; } wl_iw_ss_cache_ctrl_t; +typedef enum broadcast_first_scan { + BROADCAST_SCAN_FIRST_IDLE = 0, + BROADCAST_SCAN_FIRST_STARTED, + BROADCAST_SCAN_FIRST_RESULT_READY, + BROADCAST_SCAN_FIRST_RESULT_CONSUMED +} broadcast_first_scan_t; +#ifdef SOFTAP +#define SSID_LEN 33 +#define SEC_LEN 16 +#define KEY_LEN 65 +#define PROFILE_OFFSET 32 +struct ap_profile { + uint8 ssid[SSID_LEN]; + uint8 sec[SEC_LEN]; + uint8 key[KEY_LEN]; + uint32 channel; + uint32 preamble; + uint32 max_scb; +}; +#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_ENABLED 1 +#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 + #if WIRELESS_EXT > 12 #include <net/iw_handler.h> extern const struct iw_handler_def wl_iw_handler_def; @@ -118,12 +169,6 @@ 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); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ |