diff options
author | Howard M. Harte <hharte@broadcom.com> | 2011-05-19 09:57:48 -0700 |
---|---|---|
committer | Howard M. Harte <hharte@broadcom.com> | 2011-05-19 09:59:21 -0700 |
commit | ca0b09d37a38651a0d4f4e10f681cea35bdd89a9 (patch) | |
tree | df38f0cdf4181aaa21fb89f5f7377a6a9998b619 | |
parent | 5a9fa0a3f89b1d07d6e773a24b7f3a9aa8a18f7c (diff) | |
download | broadcom-ca0b09d37a38651a0d4f4e10f681cea35bdd89a9.tar.gz |
Update driver to 5.90.125.14.
Change-Id: I20ea59ce451d70118c6fead8a7372ce37b8be179
120 files changed, 34773 insertions, 6120 deletions
diff --git a/src/Android.mk b/src/Android.mk index 790da7a..da45564 100644 --- a/src/Android.mk +++ b/src/Android.mk @@ -1,7 +1,7 @@ # # Copyright (C) 2008 Broadcom Corporation # -# $Id: Android.mk,v 2.1.4.3 2009/05/07 18:48:19 Exp $ +# $Id: Android.mk,v 2.6 2009-05-07 18:25:15 Exp $ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/src/GNUmakefile.inc b/src/GNUmakefile.inc index 6e810cc..1750bf0 100644 --- a/src/GNUmakefile.inc +++ b/src/GNUmakefile.inc @@ -4,7 +4,7 @@ # and sources(windows style makefile). it doesn't depend on # Makerules.env except to get SRCBASE if not yet defined. # -# $Id: GNUmakefile.inc,v 1.103.76.1 2009/04/01 01:02:07 Exp $ +# $Id: GNUmakefile.inc,v 1.105 2009-04-16 00:20:28 Exp $ SHELL=bash export SHELL diff --git a/src/Makerules b/src/Makerules index b71b4f4..672a898 100644 --- a/src/Makerules +++ b/src/Makerules @@ -2,27 +2,32 @@ # Top level Makerules # it uses Makerules.env for build env vars and optional branding.inc # -# Copyright (C) 1999-2009, Broadcom Corporation -# -# Unless you and Broadcom execute a separate written software license -# agreement governing use of this software, this software is licensed to you -# under the terms of the GNU General Public License version 2 (the "GPL"), -# available at http://www.broadcom.com/licenses/GPLv2.php, with the -# following added to such license: -# -# As a special exception, the copyright holders of this software give you -# permission to link this software with independent modules, and to copy and -# distribute the resulting executable under terms of your choice, provided that -# you also meet, for each linked independent module, the terms and conditions of -# the license of that module. An independent module is a module which is not -# derived from this software. The special exception does not apply to any -# modifications of the software. -# -# 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. +# Copyright (C) 1999-2011, Broadcom Corporation +# +# Unless you and Broadcom execute a separate written software license +# agreement governing use of this software, this software is licensed to you +# under the terms of the GNU General Public License version 2 (the "GPL"), +# available at http://www.broadcom.com/licenses/GPLv2.php, with the +# following added to such license: +# +# As a special exception, the copyright holders of this software give you +# permission to link this software with independent modules, and to copy and +# distribute the resulting executable under terms of your choice, provided that +# you also meet, for each linked independent module, the terms and conditions of +# the license of that module. An independent module is a module which is not +# derived from this software. The special exception does not apply to any +# modifications of the software. +# +# 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: Makerules,v 2.69.30.3.16.3 2008/12/22 01:26:36 Exp $ +# $Id: Makerules,v 2.78.42.1 2010-05-11 17:55:55 Exp $ + +# This is the TOP level makefile rules, which is used by many makefiles. +# Please be cautious on changes, especially compatibilities. +# e.g. new gcc compile option should be protected with version check +# or "check_gcc" trick # first rule (default) all: @@ -94,8 +99,12 @@ ifeq ($(TARGETOS), unix) ifneq (,$(findstring 10.5,$(MACOS_VER))) SDK=/Developer/SDKs/MacOSX10.5.sdk else + ifneq (,$(findstring 10.6,$(MACOS_VER))) + SDK=/Developer/SDKs/MacOSX10.6.sdk + else SDK=/Developer/SDKs/MacOSX10.4u.sdk endif + endif GCDEFS := $(GCDEFS) -DMACOSX GCDEFS := $(GCDEFS) -pipe -fpascal-strings -fasm-blocks -fmessage-length=0 @@ -120,6 +129,9 @@ ifeq ($(TARGETOS), unix) ifeq ($(TARGETENV), linuxmips) TARGET_PREFIX = mipsel-linux- else + ifeq ($(TARGETENV), linux26mips) + TARGET_PREFIX = mipsel-linux-linux26- + else ifeq ($(TARGETENV), linuxmips_be) TARGET_PREFIX = mips-linux- else @@ -131,11 +143,11 @@ ifeq ($(TARGETOS), unix) else ifeq ($(TARGETENV), android) TARGET_PREFIX = arm-eabi- - GCFLAGS += -Dlinux - GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/include - GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/arch-arm/include/ - GCFLAGS += -I/tools/linux/src/linux-2.6.25-01843-gfea26b0/include/ - + GCFLAGS += -Dlinux + GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/android-ndk-r3/build/platforms/android-3/arch-arm/usr/include +# GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/include +# GCFLAGS += -I/projects/hnd/tools/linux/hndtools-arm-eabi-4.2.1/arm-eabi/include/bionic/libc/arch-arm/include/ + GCFLAGS += -I/tools/linux/src/linux-2.6.25-01843-gfea26b0/include/ else TARGET_PREFIX = endif @@ -143,6 +155,7 @@ ifeq ($(TARGETOS), unix) endif endif endif + endif CC = $(TARGET_PREFIX)gcc AS = $(TARGET_PREFIX)as @@ -354,10 +367,14 @@ ifeq ($(TARGETENV), nucleusarm) $(error "Unknown target CPU type!") endif + #CPPFLAGS := -embeddedcplusplus + CC_TARGET =-o $@ + CPP_TARGET =-o $@ LINK_TARGET =-o $@ CC := tcc + CPP := tcpp AS := armasm LD := armlink AR := armar -c -r --create @@ -490,6 +507,13 @@ ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1) ${FILTER_DEPENDS} endif +$(OBJDIR)%$(OBJEXT): %.cpp + $(CPP) -c $(CFLAGS) $(CPPFLAGS) $(CPP_TARGET) $< +ifeq ($(FILTER_DEPENDS_IN_C_TO_OBJ_RULE),1) + ${FILTER_DEPENDS} +endif + + endif # klsi %.h: %.x diff --git a/src/Makerules.env b/src/Makerules.env index 07693f6..4d8a82a 100644 --- a/src/Makerules.env +++ b/src/Makerules.env @@ -1,5 +1,5 @@ #******************************************************************************* -# $Id: Makerules.env,v 2.30.252.2 2008/12/19 05:17:58 Exp $ +# $Id: Makerules.env,v 2.34 2009-04-10 04:27:33 Exp $ # Top-level Makerules for defining environment variables # can be included by anyone doing software at Epigram #******************************************************************************* @@ -13,11 +13,11 @@ ifndef HOSTENV # Figure what type of host we are in. UNAME = $(shell uname) - ifneq ($(findstring $(UNAME), "FreeBSD NetBSD"), ) + ifneq ($(findstring "$(UNAME)", "FreeBSD" "NetBSD"), ) HOSTENV = freebsd HOSTOS = unix else - ifneq ($(findstring $(UNAME), "sun4 SunOS"), ) + ifneq ($(findstring "$(UNAME)", "sun4" "SunOS"), ) HOSTENV = sun4 HOSTOS = unix else @@ -25,7 +25,7 @@ ifndef HOSTENV HOSTENV = linux HOSTOS = unix else - ifneq ($(findstring $(UNAME), "CYGWIN32_NT CYGWIN32/NT i386 CYGWIN_NT-4.0 CYGWIN_NT-5.0 CYGWIN_NT-5.1 CYGWIN_NT-5.2 i586 i686"), ) + ifneq ($(findstring "$(UNAME)", "CYGWIN32_NT" "CYGWIN32/NT" "i386" "CYGWIN_NT-4.0" "CYGWIN_NT-5.0" "CYGWIN_NT-5.1" "CYGWIN_NT-5.2" "i586" "i686"), ) HOSTENV = Windows_NT HOSTOS = Windows_NT else @@ -45,7 +45,7 @@ endif export HOSTENV export HOSTOS -# TARGETENV is one of freebsd, sun4, linux, linuxarm, android, linuxmips, cygwin32, win32, or macos +# TARGETENV is one of freebsd, sun4, linux, linuxarm, android, linuxmips, linuxmips_be, cygwin32, win32, or macos # TARGETENV defaults to HOSTENV unless HOSTENV is Windows_NT, in # which case it defaults to win32. @@ -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" "linuxmips" "linux26mips" "linuxmips_be" "sun4" "cygwin32" "win32" "macos"), ) TARGETOS = $(HOSTOS) endif ifeq ($(TARGETENV), bcmmips) @@ -82,24 +82,24 @@ export TARGETOS # For the x86* family, a generic x86 is assuemd if not otherwise specified # Order is important since "linux" matches both linuxmips and linux. ifndef TARGETARCH - ifneq ($(findstring $(TARGETENV), "android"), ) + ifneq ($(findstring "$(TARGETENV)", "android"), ) TARGETARCH = arm_android endif - ifneq ($(findstring $(TARGETENV), "linuxarm_le"), ) + ifneq ($(findstring "$(TARGETENV)", "linuxarm_le"), ) TARGETARCH = arm_le endif - ifneq ($(findstring $(TARGETENV), "linuxarm nucleusarm"), ) + ifneq ($(findstring "$(TARGETENV)", "linuxarm nucleusarm"), ) TARGETARCH = arm endif - ifneq ($(findstring $(TARGETENV), "bcmmips linuxmips"), ) + ifneq ($(findstring "$(TARGETENV)", "bcmmips" "linuxmips" "linuxmips_be" "linux26mips"), ) TARGETARCH = mips endif - ifneq ($(findstring $(TARGETENV), "sun4"), ) + ifneq ($(findstring "$(TARGETENV)", "sun4"), ) TARGETARCH = sparc endif - ifneq ($(findstring $(TARGETENV), "freebsd linux cygwin32 win32"), ) + ifneq ($(findstring "$(TARGETENV)", "freebsd" "linux" "cygwin32" "win32"), ) TARGETCPU = $(shell uname -m) - ifneq ($(findstring $(TARGETCPU), "sparc sparc64"), ) + ifneq ($(findstring "$(TARGETCPU)", "sparc" "sparc64"), ) TARGETARCH = $(TARGETCPU) else TARGETARCH = x86_mmx @@ -107,7 +107,7 @@ ifndef TARGETARCH endif ifeq ($(TARGETENV), macos) TARGETCPU = $(shell uname -p) - ifneq ($(findstring $(TARGETCPU), "powerpc"), ) + ifneq ($(findstring "$(TARGETCPU)", "powerpc"), ) TARGETARCH = PPC else TARGETARCH = x86 diff --git a/src/bcmsdio/linux/Makefile b/src/bcmsdio/linux/Makefile index ed442a7..6671510 100644 --- a/src/bcmsdio/linux/Makefile +++ b/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-2011, 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.5.8.4.20.1 2009/01/16 18:08:37 Exp $ +# $Id: Makefile,v 1.12 2009-04-09 19:40:51 Exp $ # # Try a couple of places for LINUXDIR if not specified diff --git a/src/bcmsdio/linux/makefile.26 b/src/bcmsdio/linux/makefile.26 index 7e58cb6..176a005 100644 --- a/src/bcmsdio/linux/makefile.26 +++ b/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-2011, 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: makefile.26,v 1.2.22.2 2008/05/07 00:20:04 Exp $ +# $Id: makefile.26,v 1.4 2008-05-07 00:22:16 Exp $ obj-m += bcmsdh_driver.o bcmsdh_driver-objs = $(BCMSDHOFILES) diff --git a/src/bcmsdio/sys/bcmpcispi.c b/src/bcmsdio/sys/bcmpcispi.c index e491a90..ef59607 100644 --- a/src/bcmsdio/sys/bcmpcispi.c +++ b/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-2011, 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: bcmpcispi.c,v 1.22.2.4.4.5 2008/07/09 21:23:30 Exp $ + * $Id: bcmpcispi.c,v 1.33 2008-07-14 22:44:30 Exp $ */ #include <typedefs.h> @@ -606,18 +606,23 @@ spi_spinbits(sdioh_info_t *sd) spin_count = 0; while ((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0) { if (spin_count > SPI_SPIN_BOUND) { - ASSERT(FALSE); /* Spin bound exceeded */ + sd_err(("%s: SPIH_WFEMPTY spin bits out of bound %u times \n", + __FUNCTION__, spin_count)); + ASSERT(FALSE); } spin_count++; } - spin_count = 0; + /* Wait for SPI Transfer state machine to return to IDLE state. * The state bits are only implemented in Rev >= 5 FPGA. These * bits are hardwired to 00 for Rev < 5, so this check doesn't cause * any problems. */ + spin_count = 0; while ((SPIPCI_RREG(osh, ®s->spih_stat) & SPIH_STATE_MASK) != 0) { if (spin_count > SPI_SPIN_BOUND) { + sd_err(("%s: SPIH_STATE_MASK spin bits out of bound %u times \n", + __FUNCTION__, spin_count)); ASSERT(FALSE); } spin_count++; diff --git a/src/bcmsdio/sys/bcmsdh.c b/src/bcmsdio/sys/bcmsdh.c index a59789b..fc68b64 100644 --- a/src/bcmsdio/sys/bcmsdh.c +++ b/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-2011, 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.16.10 2009/10/05 05:55:47 Exp $ + * $Id: bcmsdh.c,v 1.57.6.4 2010-12-23 01:13:15 Exp $ */ /* ****************** BCMSDH Interface Functions *************************** */ @@ -40,6 +40,7 @@ #include <sdio.h> /* sdio spec */ +#define SDIOH_API_ACCESS_RETRY_LIMIT 2 const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; @@ -55,6 +56,17 @@ struct bcmsdh_info /* local copy of bcm sd handler */ 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); + +void +bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) +{ + sdioh_enable_hw_oob_intr(sdh->sdioh, enable); +} +#endif + bcmsdh_info_t * bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) { @@ -189,27 +201,30 @@ bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) return BCME_UNSUPPORTED; } -#define SDIOH_API_ACCESS_RETRY_LIMIT 1 uint8 bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; SDIOH_API_RC status; - uint8 data = 0; +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT int32 retry = 0; +#endif + uint8 data = 0; if (!bcmsdh) bcmsdh = l_bcmsdh; ASSERT(bcmsdh->init_success); +#ifdef SDIOH_API_ACCESS_RETRY_LIMIT do { - if (retry) - /* we wait for 1 ms till bus gets settled down */ + if (retry) /* wait for 1 ms till bus get settled down */ OSL_DELAY(1000); - - status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); - } while (!SDIOH_API_SUCCESS(status) && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); +#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); @@ -224,20 +239,24 @@ 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) - /* we wait for 1 ms till bus gets settled down */ + if (retry) /* wait for 1 ms till bus get settled down */ OSL_DELAY(1000); - - status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); - } while (!SDIOH_API_SUCCESS(status) && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); +#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; @@ -353,7 +372,7 @@ bcmsdh_reg_read(void *sdh, uint32 addr, uint size) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; SDIOH_API_RC status; - uint32 word; + uint32 word = 0; uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); @@ -575,6 +594,16 @@ bcmsdh_stop(void *sdh) return sdioh_stop(bcmsdh->sdioh); } +int +bcmsdh_waitlockfree(void *sdh) +{ + bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; + if (!bcmsdh) + bcmsdh = l_bcmsdh; + + return sdioh_waitlockfree(bcmsdh->sdioh); +} + int bcmsdh_query_device(void *sdh) diff --git a/src/bcmsdio/sys/bcmsdh_linux.c b/src/bcmsdio/sys/bcmsdh_linux.c index 58903b8..e2f35e9 100644 --- a/src/bcmsdio/sys/bcmsdh_linux.c +++ b/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-2011, 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.11.4.11 2009/10/05 05:55:47 Exp $ + * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $ */ /** @@ -42,13 +42,12 @@ #include <bcmdevs.h> #if defined(OOB_INTR_ONLY) -#include <mach/gpio.h> #include <linux/irq.h> extern void dhdsdio_isr(void * args); +#include <bcmutils.h> #include <dngl_stats.h> #include <dhd.h> #endif /* defined(OOB_INTR_ONLY) */ - #if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270) #if !defined(BCMPLATFORM_BUS) #define BCMPLATFORM_BUS @@ -76,6 +75,11 @@ struct bcmsdh_hc { bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ void *ch; unsigned int oob_irq; + unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ + bool oob_irq_registered; +#if defined(OOB_INTR_ONLY) + spinlock_t irq_lock; +#endif }; static bcmsdh_hc_t *sdhcinfo = NULL; @@ -176,6 +180,7 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ int irq = 0; uint32 vendevid; + unsigned long irq_flags = 0; #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) pdev = to_platform_device(dev); @@ -186,13 +191,20 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ #if defined(OOB_INTR_ONLY) - irq = dhd_customer_oob_irq_map(); +#ifdef HW_OOB + irq_flags = + IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; +#else + irq_flags = IRQF_TRIGGER_FALLING; +#endif /* HW_OOB */ + + /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ + irq = dhd_customer_oob_irq_map(&irq_flags); if (irq < 0) { SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); return 1; } #endif /* defined(OOB_INTR_ONLY) */ - /* allocate SDIO Host Controller state info */ if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) { SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__)); @@ -224,6 +236,11 @@ int bcmsdh_probe(struct device *dev) #endif /* BCMLXSDMMC */ sdhc->sdh = sdh; sdhc->oob_irq = irq; + sdhc->oob_flags = irq_flags; + sdhc->oob_irq_registered = FALSE; /* to make sure.. */ +#if defined(OOB_INTR_ONLY) + spin_lock_init(&sdhc->irq_lock); +#endif /* chain SDIO Host Controller info together */ sdhc->next = sdhcinfo; @@ -286,9 +303,9 @@ int bcmsdh_remove(struct device *dev) MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); osl_detach(osh); -#if !defined(BCMLXSDMMC) +#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) dev_set_drvdata(dev, NULL); -#endif /* !defined(BCMLXSDMMC) */ +#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) */ return 0; } @@ -333,12 +350,15 @@ static struct pci_driver bcmsdh_pci_driver = { }; -extern uint sd_pci_slot; -/* Force detection to a particular PCI slot only */ -/* Allow for having multiple WL devices at once in a PC */ -/* Only one instance will be useable at a time */ -/* Upper word is bus number, lower word is slot number */ -/* Default value of 0xFFFFffff turns this off */ +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 */ + /* usable at a time */ + /* Upper word is bus number, */ + /* lower word is slot number */ + /* Default value of 0xffffffff turns this */ + /* off */ module_param(sd_pci_slot, uint, 0); @@ -357,16 +377,24 @@ 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, vendor %X, device %X (but want bus %X: slot %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, sd_pci_slot>>16,sd_pci_slot&0xffff)); + 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)); + __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) || @@ -427,7 +455,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); rc = pci_enable_device(pdev); if (rc) { - SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__)); + SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__)); goto err; } if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0), @@ -454,10 +482,11 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* error handling */ err: - if (sdhc->sdh) - bcmsdh_detach(sdhc->osh, sdhc->sdh); - if (sdhc) + if (sdhc) { + if (sdhc->sdh) + bcmsdh_detach(sdhc->osh, sdhc->sdh); MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); + } if (osh) osl_detach(osh); return -ENODEV; @@ -555,20 +584,35 @@ bcmsdh_unregister(void) } #if defined(OOB_INTR_ONLY) +void bcmsdh_oob_intr_set(bool enable) +{ + static bool curstate = 1; + unsigned long flags; + + spin_lock_irqsave(&sdhcinfo->irq_lock, flags); + if (curstate != enable) { + if (enable) + enable_irq(sdhcinfo->oob_irq); + else + disable_irq_nosync(sdhcinfo->oob_irq); + curstate = enable; + } + spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags); +} + static irqreturn_t wlan_oob_irq(int irq, void *dev_id) { dhd_pub_t *dhdp; - dhdp = (dhd_pub_t *)sdhcinfo->dev->driver_data; + dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev); + + bcmsdh_oob_intr_set(0); if (dhdp == NULL) { - disable_irq(sdhcinfo->oob_irq); SDLX_MSG(("Out of band GPIO interrupt fired way too early\n")); return IRQ_HANDLED; } - WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); - dhdsdio_isr((void *)dhdp->bus); return IRQ_HANDLED; @@ -578,37 +622,52 @@ int bcmsdh_register_oob_intr(void * dhdp) { int error = 0; - SDLX_MSG(("%s Enter\n", __FUNCTION__)); + SDLX_MSG(("%s Enter \n", __FUNCTION__)); - sdhcinfo->dev->driver_data = dhdp; + /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */ - set_irq_wake(sdhcinfo->oob_irq, 1); + 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, IRQF_TRIGGER_FALLING, - "bcmsdh_sdmmc", NULL); + if (!sdhcinfo->oob_irq_registered) { + SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, + (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags)); + /* Refer to customer Host IRQ docs about proper irqflags definition */ + error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags, + "bcmsdh_sdmmc", NULL); + if (error) + return -ENODEV; - if (error) - return -ENODEV; + set_irq_wake(sdhcinfo->oob_irq, 1); + sdhcinfo->oob_irq_registered = TRUE; + } return 0; } -void bcmsdh_unregister_oob_intr(void) +void bcmsdh_set_irq(int flag) { - SDLX_MSG(("%s: Enter\n", __FUNCTION__)); - - set_irq_wake(sdhcinfo->oob_irq, 0); - disable_irq(sdhcinfo->oob_irq); /* just in case.. */ - free_irq(sdhcinfo->oob_irq, NULL); + if (sdhcinfo->oob_irq_registered) { + SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag)); + if (flag) { + enable_irq(sdhcinfo->oob_irq); + set_irq_wake(sdhcinfo->oob_irq, 1); + } else { + set_irq_wake(sdhcinfo->oob_irq, 0); + disable_irq(sdhcinfo->oob_irq); + } + } } -void bcmsdh_oob_intr_set(bool enable) +void bcmsdh_unregister_oob_intr(void) { - if (enable) - enable_irq(sdhcinfo->oob_irq); - else - disable_irq(sdhcinfo->oob_irq); + SDLX_MSG(("%s: Enter\n", __FUNCTION__)); + + if (sdhcinfo->oob_irq_registered == TRUE) { + set_irq_wake(sdhcinfo->oob_irq, 0); + disable_irq(sdhcinfo->oob_irq); /* just in case.. */ + free_irq(sdhcinfo->oob_irq, NULL); + sdhcinfo->oob_irq_registered = FALSE; + } } #endif /* defined(OOB_INTR_ONLY) */ /* Module parameters specific to each host-controller driver */ @@ -667,6 +726,7 @@ EXPORT_SYMBOL(bcmsdh_register); EXPORT_SYMBOL(bcmsdh_unregister); EXPORT_SYMBOL(bcmsdh_chipmatch); EXPORT_SYMBOL(bcmsdh_reset); +EXPORT_SYMBOL(bcmsdh_waitlockfree); EXPORT_SYMBOL(bcmsdh_get_dstatus); EXPORT_SYMBOL(bcmsdh_cfg_read_word); diff --git a/src/bcmsdio/sys/bcmsdh_sdmmc.c b/src/bcmsdio/sys/bcmsdh_sdmmc.c index 5d70d7b..d5a403e 100644 --- a/src/bcmsdio/sys/bcmsdh_sdmmc.c +++ b/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-2011, 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.8.6.22 2009/10/09 11:48:34 Exp $ + * $Id: bcmsdh_sdmmc.c,v 1.14.64.3 2010-12-23 01:13:15 Exp $ */ #include <typedefs.h> @@ -35,8 +35,6 @@ #include <sdiovar.h> /* ioctl/iovars */ #include <linux/mmc/core.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> @@ -57,7 +55,7 @@ extern void sdio_function_cleanup(void); #if !defined(OOB_INTR_ONLY) static void IRQHandler(struct sdio_func *func); static void IRQHandlerF2(struct sdio_func *func); -#endif +#endif /* !defined(OOB_INTR_ONLY) */ static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); extern int sdio_reset_comm(struct mmc_card *card); @@ -212,6 +210,70 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) return SDIOH_API_RC_SUCCESS; } +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +extern SDIOH_API_RC +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], 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; + } + + /* Enable F1 and F2 interrupts, set master enable */ + reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN); + + 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; + } + } + + return SDIOH_API_RC_SUCCESS; +} + +extern SDIOH_API_RC +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], 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 &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); + /* Disable master interrupt with the last function interrupt */ + if (!(reg & 0xFE)) + reg = 0; + 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; + } + } + return SDIOH_API_RC_SUCCESS; +} +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + /* 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) @@ -238,7 +300,10 @@ sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) sdio_claim_irq(gInstance->func[1], IRQHandler); sdio_release_host(gInstance->func[1]); } +#elif defined(HW_OOB) + sdioh_enable_func_intr(); #endif /* !defined(OOB_INTR_ONLY) */ + return SDIOH_API_RC_SUCCESS; } @@ -266,6 +331,8 @@ sdioh_interrupt_deregister(sdioh_info_t *sd) sd->intr_handler_valid = FALSE; sd->intr_handler = NULL; sd->intr_handler_arg = NULL; +#elif defined(HW_OOB) + sdioh_disable_func_intr(); #endif /* !defined(OOB_INTR_ONLY) */ return SDIOH_API_RC_SUCCESS; } @@ -597,6 +664,29 @@ exit: return bcmerror; } +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) + +SDIOH_API_RC +sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) +{ + SDIOH_API_RC status; + uint8 data; + + if (enable) + data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; /* enable hw oob interrupt */ + else + data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ + +#if 1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + /* Needed for Android Linux Kernel 2.6.35 */ + data |= SDIO_SEPINT_ACT_HI; /* Active HIGH */ +#endif /* OEM_ANDROID */ + + status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); + return status; +} +#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) { @@ -712,11 +802,10 @@ 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 +#endif /* MMC_SDIO_ABORT */ else if (regaddr < 0xF0) { sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); } else { @@ -908,7 +997,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u if (pkt == NULL) { sd_data(("%s: Creating new %s Packet, len=%d\n", __FUNCTION__, write ? "TX" : "RX", buflen_u)); +#ifdef DHD_USE_STATIC_BUF + if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) { +#else if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) { +#endif /* DHD_USE_STATIC_BUF */ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buflen_u)); return SDIOH_API_RC_FAIL; @@ -925,8 +1018,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u if (!write) { bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); } - +#ifdef DHD_USE_STATIC_BUF + PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); +#else PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); +#endif /* DHD_USE_STATIC_BUF */ } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { /* Case 2: We have a packet, but it is unaligned. */ @@ -935,7 +1031,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u sd_data(("%s: Creating aligned %s Packet, len=%d\n", __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt))); +#ifdef DHD_USE_STATIC_BUF + if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { +#else if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { +#endif /* DHD_USE_STATIC_BUF */ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, PKTLEN(sd->osh, pkt))); return SDIOH_API_RC_FAIL; @@ -956,8 +1056,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u PKTDATA(sd->osh, pkt), PKTLEN(sd->osh, mypkt)); } - +#ifdef DHD_USE_STATIC_BUF + PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); +#else PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); +#endif /* DHD_USE_STATIC_BUF */ } else { /* case 3: We have a packet and it is aligned. */ sd_data(("%s: Aligned %s Packet, direct DMA\n", __FUNCTION__, write ? "Tx" : "Rx")); @@ -967,59 +1070,19 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u return (Status); } -#if defined(MMC_SDIO_ABORT) - -#if defined(DHD_DEBUG) -/* mmc kernel api : newly added for abort test purpose */ -extern int sdio_set_block_size2(struct sdio_func *func, unsigned blksz); - -/* can be used to change block size on the fly for abort test purpose */ -void -dhd_set_blk_size(unsigned int size) -{ - int err_ret; - - sdio_claim_host(gInstance->func[2]); - err_ret = sdio_set_block_size2(gInstance->func[2], size); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", - sd_f2_blocksize)); - } - sdio_release_host(gInstance->func[2]); -} -#endif /* defined(DHD_DEBUG) */ - -#define MMC_BASE_ADDR 0xc6872000 /* extracted by test for MSM SDCC */ -#define MMCICOMMAND 0x00c /* command register offset of MSM SDCC */ -#define MCI_CSPM_MCIABORT (1 << 13) /* abort bit in command register */ - -/* mmc kernel api : newly added to access sdcc command register */ -extern void msm_dhd_writel(unsigned int arg, void *base); - /* this function performs "abort" for both of host & device */ -static int -sdmmc_abort(sdioh_info_t *sd, uint func) -{ - char t_func = (char)func; - unsigned int arg; - - arg = MCI_CSPM_MCIABORT; - msm_dhd_writel(arg, (void *)(MMC_BASE_ADDR + MMCICOMMAND)); /* abort host first */ - - /* issue abort cmd52 command through F1 */ - sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); - return 0; -} -#endif /* MMC_SDIO_ABORT */ - extern int sdioh_abort(sdioh_info_t *sd, uint func) { +#if defined(MMC_SDIO_ABORT) + char t_func = (char) func; +#endif /* defined(MMC_SDIO_ABORT) */ sd_trace(("%s: Enter\n", __FUNCTION__)); #if defined(MMC_SDIO_ABORT) - sdmmc_abort(sd, func); -#endif + /* issue abort cmd52 command through F1 */ + sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); +#endif /* defined(MMC_SDIO_ABORT) */ sd_trace(("%s: Exit\n", __FUNCTION__)); return SDIOH_API_RC_SUCCESS; @@ -1037,10 +1100,6 @@ int sdioh_sdio_reset(sdioh_info_t *si) void sdioh_sdmmc_devintr_off(sdioh_info_t *sd) { - struct mmc_card *card = gInstance->func[0]->card; - struct mmc_host *host = card->host; - - host->ops->enable_sdio_irq(host, 0); /* GG */ sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); sd->intmask &= ~CLIENT_INTR; } @@ -1049,12 +1108,8 @@ sdioh_sdmmc_devintr_off(sdioh_info_t *sd) void sdioh_sdmmc_devintr_on(sdioh_info_t *sd) { - struct mmc_card *card = gInstance->func[0]->card; - struct mmc_host *host = card->host; - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); sd->intmask |= CLIENT_INTR; - host->ops->enable_sdio_irq(host, 1); } /* Read client card reg */ @@ -1092,7 +1147,6 @@ static void IRQHandler(struct sdio_func *func) sd = gInstance->sd; ASSERT(sd != NULL); - sdio_release_host(gInstance->func[0]); if (sd->use_client_ints) { @@ -1108,7 +1162,6 @@ static void IRQHandler(struct sdio_func *func) } sdio_claim_host(gInstance->func[0]); - } /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ @@ -1163,50 +1216,50 @@ sdioh_start(sdioh_info_t *si, int stage) */ if (gInstance->func[0]) { if (stage == 0) { - /* Since the power to the chip is killed, we will have - re enumerate the device again. Set the block size - and enable the fucntion 1 for in preparation for - downloading the code - */ - /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux - 2.6.27. The implementation prior to that is buggy, and needs broadcom's - patch for it - */ - if ((ret = sdio_reset_comm(gInstance->func[0]->card))) - sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); - else { - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - - /* Claim host controller */ - sdio_claim_host(gInstance->func[1]); - - sd->client_block_size[1] = 64; - if (sdio_set_block_size(gInstance->func[1], 64)) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); - } + /* Since the power to the chip is killed, we will have + re enumerate the device again. Set the block size + and enable the fucntion 1 for in preparation for + downloading the code + */ + /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux + 2.6.27. The implementation prior to that is buggy, and needs broadcom's + patch for it + */ + if ((ret = sdio_reset_comm(gInstance->func[0]->card))) + sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + else { + sd->num_funcs = 2; + sd->sd_blockmode = TRUE; + sd->use_client_ints = TRUE; + sd->client_block_size[0] = 64; + + /* Claim host controller */ + sdio_claim_host(gInstance->func[1]); + + sd->client_block_size[1] = 64; + if (sdio_set_block_size(gInstance->func[1], 64)) { + sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); + } - /* Release host controller F1 */ - sdio_release_host(gInstance->func[1]); + /* Release host controller F1 */ + sdio_release_host(gInstance->func[1]); - if (gInstance->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(gInstance->func[2]); + if (gInstance->func[2]) { + /* Claim host controller F2 */ + sdio_claim_host(gInstance->func[2]); - sd->client_block_size[2] = sd_f2_blocksize; - if (sdio_set_block_size(gInstance->func[2], - sd_f2_blocksize)) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 " - "blocksize to %d\n", sd_f2_blocksize)); - } - - /* Release host controller F2 */ - sdio_release_host(gInstance->func[2]); + sd->client_block_size[2] = sd_f2_blocksize; + if (sdio_set_block_size(gInstance->func[2], + sd_f2_blocksize)) { + sd_err(("bcmsdh_sdmmc: Failed to set F2 " + "blocksize to %d\n", sd_f2_blocksize)); } - sdioh_sdmmc_card_enablefuncs(sd); + /* Release host controller F2 */ + sdio_release_host(gInstance->func[2]); + } + + sdioh_sdmmc_card_enablefuncs(sd); } } else { #if !defined(OOB_INTR_ONLY) @@ -1214,9 +1267,12 @@ sdioh_start(sdioh_info_t *si, int stage) sdio_claim_irq(gInstance->func[2], IRQHandlerF2); sdio_claim_irq(gInstance->func[1], IRQHandler); sdio_release_host(gInstance->func[0]); -#else - bcmsdh_oob_intr_set(TRUE); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_enable_func_intr(); #endif + bcmsdh_oob_intr_set(TRUE); +#endif /* !defined(OOB_INTR_ONLY) */ } } else @@ -1228,7 +1284,6 @@ sdioh_start(sdioh_info_t *si, int stage) int sdioh_stop(sdioh_info_t *si) { - /* MSM7201A Android sdio stack has bug with interrupt So internaly within SDIO stack they are polling which cause issue when device is turned off. So @@ -1241,11 +1296,20 @@ sdioh_stop(sdioh_info_t *si) sdio_release_irq(gInstance->func[1]); sdio_release_irq(gInstance->func[2]); sdio_release_host(gInstance->func[0]); -#else - bcmsdh_oob_intr_set(FALSE); +#else /* defined(OOB_INTR_ONLY) */ +#if defined(HW_OOB) + sdioh_disable_func_intr(); #endif + bcmsdh_oob_intr_set(FALSE); +#endif /* !defined(OOB_INTR_ONLY) */ } else sd_err(("%s Failed\n", __FUNCTION__)); return (0); } + +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return (1); +} diff --git a/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c index 2f9c926..b35859d 100644 --- a/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c +++ b/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-2011, 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.20.11 2009/09/30 21:55:16 Exp $ + * $Id: bcmsdh_sdmmc_linux.c,v 1.8.6.2 2011-02-01 18:38:36 Exp $ */ #include <typedefs.h> @@ -39,14 +39,30 @@ #if !defined(SDIO_VENDOR_ID_BROADCOM) #define SDIO_VENDOR_ID_BROADCOM 0x02d0 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ +#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ + +#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 + +#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) +#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ #if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -#define SDIO_DEVICE_ID_BROADCOM_4325 0x0000 +#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) +#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) +#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ #include <bcmsdh_sdmmc.h> + #include <dhd_dbg.h> +#ifdef WL_CFG80211 +extern void wl_cfg80211_set_sdio_func(void *func); +#endif extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); @@ -72,11 +88,11 @@ extern int bcmsdh_probe(struct device *dev); extern int bcmsdh_remove(struct device *dev); struct device sdmmc_dev; - 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)); @@ -84,8 +100,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")); @@ -96,6 +113,9 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, gInstance->func[func->num] = func; if (func->num == 2) { +#ifdef WL_CFG80211 + wl_cfg80211_set_sdio_func(func); +#endif sd_trace(("F2 found, calling bcmsdh_probe...\n")); ret = bcmsdh_probe(&sdmmc_dev); } @@ -112,15 +132,18 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func) sd_info(("Function#: 0x%04x\n", func->num)); if (func->num == 2) { - sd_trace(("F2 found, calling bcmsdh_probe...\n")); + sd_trace(("F2 found, calling bcmsdh_remove...\n")); bcmsdh_remove(&sdmmc_dev); } } - /* devices we support, null terminated */ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, { /* end: all zeroes */ }, }; @@ -164,13 +187,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 @@ -257,6 +273,7 @@ void sdio_function_cleanup(void) { sd_trace(("%s Enter\n", __FUNCTION__)); + sdio_unregister_driver(&bcmsdh_sdmmc_driver); if (gInstance) diff --git a/src/bcmsdio/sys/bcmsdspi.c b/src/bcmsdio/sys/bcmsdspi.c index 4cb0b22..95e9850 100644 --- a/src/bcmsdio/sys/bcmsdspi.c +++ b/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-2011, 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.20.4 2009/09/24 01:28:41 Exp $ + * $Id: bcmsdspi.c,v 1.25.6.1 2010-08-26 19:11:15 Exp $ */ #include <typedefs.h> @@ -708,6 +708,12 @@ sdioh_stop(sdioh_info_t *sd) return SUCCESS; } +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + return SUCCESS; +} + /* * Private/Static work routines diff --git a/src/bcmsdio/sys/bcmsdspi_linux.c b/src/bcmsdio/sys/bcmsdspi_linux.c index e76a66f..c13d01d 100644 --- a/src/bcmsdio/sys/bcmsdspi_linux.c +++ b/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-2011, 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_linux.c,v 1.7.2.1.4.3 2008/06/30 21:09:36 Exp $ + * $Id: bcmsdspi_linux.c,v 1.11 2008-06-30 21:41:11 Exp $ */ #include <typedefs.h> diff --git a/src/bcmsdio/sys/bcmsdstd.c b/src/bcmsdio/sys/bcmsdstd.c index d322eb7..94d7923 100644 --- a/src/bcmsdio/sys/bcmsdstd.c +++ b/src/bcmsdio/sys/bcmsdstd.c @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.6.4.7 2009/09/24 01:28:41 Exp $ + * $Id: bcmsdstd.c,v 1.87.2.19 2011-01-08 05:31:39 Exp $ */ #include <typedefs.h> @@ -32,13 +32,14 @@ #include <osl.h> #include <siutils.h> #include <sdio.h> /* SDIO Device and Protocol Specs */ -#include <sdioh.h> /* SDIO Host Controller Specification */ +#include <sdioh.h> /* SDIO Standard Host Controller Specification */ #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ #include <sdiovar.h> /* ioctl/iovars */ #include <pcicfg.h> -#define SD_PAGE 4096 +#define SD_PAGE_BITS 12 +#define SD_PAGE (1 << SD_PAGE_BITS) #include <bcmsdstd.h> @@ -48,27 +49,36 @@ uint sd_hiok = TRUE; /* Use hi-speed mode if available? */ uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ uint sd_f2_blocksize = 64; /* Default blocksize */ + +#define sd3_trace(x) + + #ifdef BCMSDYIELD bool sd_yieldcpu = TRUE; /* Allow CPU yielding for buffer requests */ uint sd_minyield = 0; /* Minimum xfer size to allow CPU yield */ bool sd_forcerb = FALSE; /* Force sync readback in intrs_on/off */ #endif -uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ +uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz + :might get changed in code for 208 + */ 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 uint16 sdstd_start_power(sdioh_info_t *sd, int volts_req); 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); @@ -85,6 +95,18 @@ 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); + + +static int sdstd_clock_wrapper(sdioh_info_t *sd); + + /* * Private register access routines. @@ -106,7 +128,7 @@ extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data); void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data) { - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16) data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16) data; sd_ctrl(("16: W Reg 0x%02x, Data 0x%x\n", reg, data)); } @@ -116,7 +138,7 @@ sdstd_or_reg16(sdioh_info_t *sd, uint reg, uint16 val) volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg); sd_ctrl(("16: OR Reg 0x%02x, Val 0x%x\n", reg, val)); data |= val; - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data; } static void @@ -127,7 +149,7 @@ sdstd_mod_reg16(sdioh_info_t *sd, uint reg, int16 mask, uint16 val) sd_ctrl(("16: MOD Reg 0x%02x, Mask 0x%x, Val 0x%x\n", reg, mask, val)); data &= ~mask; data |= (val & mask); - *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data; + *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data; } @@ -142,7 +164,7 @@ sdstd_rreg(sdioh_info_t *sd, uint reg) static inline void sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data) { - *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data; + *(volatile uint32 *)(sd->mem_space + reg) = (uint32)data; sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data)); } @@ -151,7 +173,7 @@ sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data) static inline void sdstd_wreg8(sdioh_info_t *sd, uint reg, uint8 data) { - *(volatile uint8 *)(sd->mem_space + reg) = (volatile uint8)data; + *(volatile uint8 *)(sd->mem_space + reg) = (uint8)data; sd_ctrl(("08: W Reg 0x%02x, Data 0x%x\n", reg, data)); } static uint8 @@ -206,15 +228,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 @@ -235,6 +252,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); @@ -274,7 +296,7 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd) return SDIOH_API_RC_SUCCESS; } -/* Configure callback to client when we recieve client interrupt */ +/* Configure callback to client when we receive client interrupt */ extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) { @@ -338,14 +360,14 @@ enum { IOV_YIELDCPU, IOV_MINYIELD, IOV_FORCERB, - IOV_CLOCK + IOV_CLOCK, }; 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 }, @@ -430,7 +452,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 @@ -504,12 +526,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): @@ -607,6 +630,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, bcmerror = sdstd_set_highspeed_mode(si, (bool)sd_hiok); break; + case IOV_GVAL(IOV_NUMINTS): int_val = (int32)si->intrcount; bcopy(&int_val, arg, val_size); @@ -765,7 +789,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; } @@ -817,9 +841,15 @@ 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) { + uint8 is_ddr50 = FALSE; int len; int buflen = (int)buflen_u; bool fifo = (fix_inc == SDIOH_DATA_FIX); + uint8 *localbuf = NULL, *tmpbuf = NULL; + uint tmplen = 0; + bool local_blockmode = sd->sd_blockmode; + SDIOH_API_RC status = SDIOH_API_RC_SUCCESS; + sdstd_lock(sd); @@ -834,10 +864,10 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint /* Break buffer down into blocksize chunks: * Bytemode: 1 block at a time. * Blockmode: Multiples of blocksizes at a time w/ max of SD_PAGE. - * Both: leftovers are handled last (will be sent via bytemode.) + * 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); @@ -845,26 +875,55 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint if (buflen > sd->client_block_size[func]) len = (len/sd->client_block_size[func]) * sd->client_block_size[func]; + if ((func == SDIO_FUNC_1) && (((len % 4) == 3) || (((len % 2) == 1) && + (is_ddr50))) && (rw == SDIOH_WRITE)) { + tmplen = len; + sd_err(("%s: Rounding up buffer to mod4 length.\n", __FUNCTION__)); + len++; + tmpbuf = buffer; + if ((localbuf = (uint8 *)MALLOC(sd->osh, len)) == NULL) { + sd_err(("out of memory, malloced %d bytes\n", + MALLOCED(sd->osh))); + status = SDIOH_API_RC_FAIL; + goto done; + } + bcopy(buffer, localbuf, len); + buffer = localbuf; + } } else { /* Byte mode: One block at a time */ len = MIN(sd->client_block_size[func], buflen); } if (sdstd_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - sdstd_unlock(sd); - return SDIOH_API_RC_FAIL; + status = SDIOH_API_RC_FAIL; + goto done; + } + + if (local_blockmode) { + if ((func == SDIO_FUNC_1) && (((tmplen % 4) == 3) || (((len % 2) == 1) && + (is_ddr50))) && (rw == SDIOH_WRITE)) { + if (localbuf) + MFREE(sd->osh, localbuf, len); + len--; + buffer = tmpbuf; + sd_err(("%s: Restoring back buffer ptr and len.\n", __FUNCTION__)); + } } + buffer += len; buflen -= len; if (!fifo) addr += len; } +done: sdstd_unlock(sd); - return SDIOH_API_RC_SUCCESS; + + return status; } -static -int sdstd_abort(sdioh_info_t *sd, uint func) +static int +sdstd_abort(sdioh_info_t *sd, uint func) { int err = 0; int retries; @@ -926,6 +985,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 */ @@ -1034,6 +1098,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)); @@ -1077,6 +1144,13 @@ sdioh_stop(sdioh_info_t *sd) return SUCCESS; } +int +sdioh_waitlockfree(sdioh_info_t *sd) +{ + sdstd_waitlockfree(sd); + return SUCCESS; +} + static int sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg) { @@ -1107,6 +1181,9 @@ sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg) /* On data error, issue DAT reset */ if (regval & ERRINT_DATA_ERRS) { + if (regval & ERRINT_ADMA_BIT) + sd_err(("%s:ADMAError: status:0x%x\n", + __FUNCTION__, sdstd_rreg(sdioh_info, SD_ADMA_ErrStatus))); sd_trace(("%s: issuing DAT reset\n", __FUNCTION__)); sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_DAT, 1)); for (retries = RETRIES_LARGE; retries; retries--) @@ -1174,6 +1251,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; @@ -1298,7 +1376,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 @@ -1362,7 +1441,6 @@ sdstd_host_init(sdioh_info_t *sd) sdstd_rreg16(sd, SD_HostControllerVersion) >> 8)); break; case 1: - case 2: sd_err(("Host Controller version 2.0, Vendor Revision: 0x%02x\n", sdstd_rreg16(sd, SD_HostControllerVersion) >> 8)); break; @@ -1375,22 +1453,19 @@ 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; - } + sd_info(("%s: caps: 0x%x; MCCap:0x%x\n", __FUNCTION__, sd->caps, sd->curr_caps)); + + 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 */ @@ -1400,6 +1475,7 @@ sdstd_host_init(sdioh_info_t *sd) sd->card_init_done = FALSE; sd->adapter_slot = full_slot; + return (SUCCESS); } #define CMD5_RETRIES 200 @@ -1414,7 +1490,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; @@ -1435,29 +1511,31 @@ sdstd_client_init(sdioh_info_t *sd) uint32 cmd_arg, cmd_rsp; int status; uint8 fn_ints; + uint32 regdata; sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); /* Clear any pending ints */ - sdstd_wreg16(sd, SD_IntrStatus, 0x1ff); + sdstd_wreg16(sd, SD_IntrStatus, 0x1fff); sdstd_wreg16(sd, SD_ErrorIntrStatus, 0x0fff); /* Enable both Normal and Error Status. This does not enable * interrupts, it only enables the status bits to * become 'live' */ - sdstd_wreg16(sd, SD_IntrStatusEnable, 0x1ff); + + { + /* INT_x interrupts, but DO NOT enable signalling [enable retuning + * will happen later] + */ + sdstd_wreg16(sd, SD_IntrStatusEnable, 0x0fff); + } sdstd_wreg16(sd, SD_ErrorIntrStatusEnable, 0xffff); sdstd_wreg16(sd, SD_IntrSignalEnable, 0); /* Disable ints for now. */ - /* Start at ~400KHz clock rate for initialization */ - if (!sdstd_start_clock(sd, 128)) { - sd_err(("sdstd_start_clock failed\n")); - return ERROR; - } - if (!sdstd_start_power(sd)) { + if (TRUE != sdstd_start_power(sd, 0)) { sd_err(("sdstd_start_power failed\n")); return ERROR; } @@ -1470,7 +1548,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; @@ -1482,7 +1560,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; @@ -1508,7 +1586,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; @@ -1521,6 +1599,21 @@ sdstd_client_init(sdioh_info_t *sd) } } + /* Disable default/power-up device Card Detect (CD) pull up resistor on DAT3 + * via CCCR bus interface control register. Set CD disable bit while leaving + * others alone. + */ + if (sdstd_card_regread (sd, 0, SDIOD_CCCR_BICTRL, 1, ®data) != SUCCESS) { + sd_err(("Disabling card detect: read of device CCCR BICTRL register failed\n")); + return ERROR; + } + regdata |= BUS_CARD_DETECT_DIS; + + if (sdstd_card_regwrite (sd, 0, SDIOD_CCCR_BICTRL, 1, regdata) != SUCCESS) { + sd_err(("Disabling card detect: write of device CCCR BICTRL register failed\n")); + return ERROR; + } + sdstd_card_enablefuncs(sd); if (!sdstd_bus_width(sd, sd_sdmode)) { @@ -1545,19 +1638,32 @@ sdstd_client_init(sdioh_info_t *sd) } /* Switch to High-speed clocking mode if both host and device support it */ - sdstd_set_highspeed_mode(sd, (bool)sd_hiok); + { + if (sdstd_clock_wrapper(sd)) { + sd_err(("sdstd_start_clock failed\n")); + return ERROR; + } + } + sd->card_init_done = TRUE; + return SUCCESS; +} + +static int +sdstd_clock_wrapper(sdioh_info_t *sd) +{ + sd_trace(("%s:Enter\n", __FUNCTION__)); /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!sdstd_start_clock(sd, (uint16)sd_divisor)) { + sdstd_set_highspeed_mode(sd, (bool)sd_hiok); + + if (FALSE == sdstd_start_clock(sd, (uint16)sd_divisor)) { sd_err(("sdstd_start_clock failed\n")); return ERROR; } - - sd->card_init_done = TRUE; - return SUCCESS; } + static int sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) { @@ -1565,6 +1671,7 @@ sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) int status; uint8 reg8; + reg8 = sdstd_rreg8(sd, SD_HostCntrl); @@ -1625,32 +1732,125 @@ sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) reg8 = SFIELD(reg8, HOST_HI_SPEED_EN, 0); } + sdstd_wreg8(sd, SD_HostCntrl, reg8); 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) { uint rc, count; uint16 divisor; + uint16 regdata; + sd3_trace(("%s: starting clk\n", __FUNCTION__)); /* turn off HC clock */ sdstd_wreg16(sd, SD_ClockCntrl, sdstd_rreg16(sd, SD_ClockCntrl) & ~((uint16)0x4)); /* Disable the HC clock */ /* Set divisor */ + { + /* new logic: if divisor > 256, restrict to 256 */ + if (new_sd_divisor > 256) + new_sd_divisor = 256; + divisor = (new_sd_divisor >> 1) << 8; + } - divisor = (new_sd_divisor >> 1) << 8; sd_info(("Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl))); - sdstd_mod_reg16(sd, SD_ClockCntrl, 0xff00, divisor); - sd_info(("%s: Using clock divisor of %d (regval 0x%04x)\n", __FUNCTION__, - new_sd_divisor, divisor)); + { + sdstd_mod_reg16(sd, SD_ClockCntrl, 0xff00, divisor); + } - sd_info(("Primary Clock Freq = %d MHz\n", GFIELD(sd->caps, CAP_TO_CLKFREQ))); + sd_err(("%s: Using clock divisor of %d (regval 0x%04x)\n", __FUNCTION__, + new_sd_divisor, divisor)); + sd_err(("%s:now, divided clk is: %d Hz\n", + __FUNCTION__, GFIELD(sd->caps, CAP_BASECLK)*1000000/new_sd_divisor)); + sd_info(("Primary Clock Freq = %d MHz\n", GFIELD(sd->caps, CAP_BASECLK))); if (GFIELD(sd->caps, CAP_TO_CLKFREQ) == 50) { sd_info(("%s: Resulting SDIO clock is %d %s\n", __FUNCTION__, @@ -1668,7 +1868,7 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) } else if (sd->controller_type == SDIOH_TYPE_BCM27XX) { } else { sd_err(("Need to determine divisor for %d MHz clocks\n", - GFIELD(sd->caps, CAP_TO_CLKFREQ))); + GFIELD(sd->caps, CAP_BASECLK))); sd_err(("Consult SD Host Controller Spec: Clock Control Register\n")); return (FALSE); } @@ -1684,7 +1884,7 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) rc = (sdstd_rreg16(sd, SD_ClockCntrl) & 2); count++; if (count > 10000) { - sd_err(("%s:Clocks failed to stabilize after %u attempts", + sd_err(("%s:Clocks failed to stabilize after %u attempts\n", __FUNCTION__, count)); return (FALSE); } @@ -1692,11 +1892,11 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) /* Turn on clock */ sdstd_or_reg16(sd, SD_ClockCntrl, 0x4); + /* Set timeout control (adjust default value based on divisor). * Disabling timeout interrupts during setting is advised by host spec. */ { - uint16 regdata; uint toval; toval = sd_toctl; @@ -1712,7 +1912,6 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) sdstd_wreg8(sd, SD_TimeoutCntrl, (uint8)toval); sdstd_wreg16(sd, SD_ErrorIntrStatusEnable, regdata); } - OSL_DELAY(2); sd_info(("Final Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl))); @@ -1720,37 +1919,98 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor) return TRUE; } -bool -sdstd_start_power(sdioh_info_t *sd) +uint16 +sdstd_start_power(sdioh_info_t *sd, int volts_req) { char *s; uint32 cmd_arg; uint32 cmd_rsp; uint8 pwr = 0; - int volts; + int volts = 0; + uint16 init_divider = 0; + bool selhighest = (volts_req == 0) ? TRUE : FALSE; + + /* reset the card uhsi volt support to false */ + sd->card_UHSI_voltage_Supported = FALSE; + + /* Ensure a power on reset by turning off bus power in case it happened to + * be on already. (This might happen if driver doesn't unload/clean up correctly, + * crash, etc.) Leave off for 100ms to make sure the power off isn't + * ignored/filtered by the device. Note we can't skip this step if the power is + * off already since we don't know how long it has been off before starting + * the driver. + */ + sdstd_wreg8(sd, SD_PwrCntrl, 0); + sd_info(("Turning off VDD/bus power briefly (100ms) to ensure reset\n")); + OSL_DELAY(100000); + + /* For selecting highest available voltage, start from lowest and iterate */ + if (!volts_req) + volts_req = 1; - volts = 0; s = NULL; - if (GFIELD(sd->caps, CAP_VOLT_1_8)) { - volts = 5; - s = "1.8"; + + if (volts_req == 1) { + if (GFIELD(sd->caps, CAP_VOLT_1_8)) { + volts = 5; + s = "1.8"; + if (FALSE == selhighest) + goto voltsel; + else + volts_req++; + } else { + sd_err(("HC doesn't support voltage! trying higher voltage: %d\n", volts)); + volts_req++; + } } - if (GFIELD(sd->caps, CAP_VOLT_3_0)) { - volts = 6; - s = "3.0"; + + if (volts_req == 2) { + if (GFIELD(sd->caps, CAP_VOLT_3_0)) { + volts = 6; + s = "3.0"; + if (FALSE == selhighest) + goto voltsel; + else volts_req++; + } else { + sd_err(("HC doesn't support voltage! trying higher voltage: %d\n", volts)); + volts_req++; + } } - if (GFIELD(sd->caps, CAP_VOLT_3_3)) { - volts = 7; - s = "3.3"; + + if (volts_req == 3) { + if (GFIELD(sd->caps, CAP_VOLT_3_3)) { + volts = 7; + s = "3.3"; + } else { + if ((FALSE == selhighest) || (volts == 0)) { + sd_err(("HC doesn't support any voltage! error!\n")); + return FALSE; + } + } } + +voltsel: pwr = SFIELD(pwr, PWR_VOLTS, volts); pwr = SFIELD(pwr, PWR_BUS_EN, 1); sdstd_wreg8(sd, SD_PwrCntrl, pwr); /* Set Voltage level */ sd_info(("Setting Bus Power to %s Volts\n", s)); - /* Wait for power to stabilize, Dongle takes longer than NIC. */ - OSL_DELAY(250000); + /* Wait for 500ms for power to stabilize. Some designs have reset IC's + * which can hold reset low for close to 300ms. In addition there can + * be ramp time for VDD and/or VDDIO which might be provided from a LDO. + * For these reasons we need a pretty conservative delay here to have + * predictable reset behavior in the face of an unknown design. + */ + OSL_DELAY(500000); + + init_divider = 128; + + /* Start at ~400KHz clock rate for initialization */ + if (!sdstd_start_clock(sd, init_divider)) { + sd_err(("%s: sdstd_start_clock failed\n", __FUNCTION__)); + return FALSE; + } /* Get the Card's Operation Condition. Occasionally the board * takes a while to become ready @@ -1759,10 +2019,10 @@ sdstd_start_power(sdioh_info_t *sd) cmd_rsp = 0; if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) { sd_err(("%s: Failed to get OCR bailing\n", __FUNCTION__)); - sdstd_reset(sd, 0, 1); - return FALSE; + return SDIO_OCR_READ_FAIL; } + sd_info(("cmd_rsp = 0x%x\n", cmd_rsp)); sd_info(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT))); sd_info(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS))); sd_info(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY))); @@ -1789,6 +2049,8 @@ sdstd_start_power(sdioh_info_t *sd) cmd_rsp = 0; get_ocr(sd, &cmd_arg, &cmd_rsp); sd_info(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR))); + + return TRUE; } @@ -1821,6 +2083,7 @@ sdstd_bus_width(sdioh_info_t *sd, int new_mode) if ((status = sdstd_card_regwrite (sd, 0, SDIOD_CCCR_BICTRL, 1, regdata)) != SUCCESS) return (bool)status; + /* Set host side via Host reg */ reg8 = sdstd_rreg8(sd, SD_HostCntrl) & ~SD4_MODE; if (new_mode == SDIOH_MODE_SD4) @@ -1836,6 +2099,7 @@ static int sdstd_driver_init(sdioh_info_t *sd) { sd_trace(("%s\n", __FUNCTION__)); + sd->sd3_tuning_reqd = FALSE; if ((sdstd_host_init(sd)) != SUCCESS) { return ERROR; } @@ -1844,6 +2108,7 @@ sdstd_driver_init(sdioh_info_t *sd) return ERROR; } + return SUCCESS; } @@ -1916,7 +2181,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; @@ -1934,6 +2199,8 @@ sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n", __FUNCTION__, GFIELD(rsp5, RSP5_STUFF))); *data = GFIELD(rsp5, RSP5_DATA); + + sd_data(("%s: Resp data(0x%x)\n", __FUNCTION__, *data)); } else { cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize); cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); @@ -1947,7 +2214,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; @@ -1987,6 +2254,7 @@ sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint else *data = sdstd_rreg(sd, SD_BufferDataPort0); + sd_data(("%s: Resp data(0x%x)\n", __FUNCTION__, *data)); /* Check Status. * After the data is read, the Transfer Complete bit should be on */ @@ -2089,7 +2357,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; @@ -2112,7 +2380,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; @@ -2193,6 +2461,11 @@ sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit w } } +/* + Note: options: 0 - default + 1 - tuning option: Means that, this cmd issue is as a part + of tuning. So no need to check the start tuning function. +*/ static int sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg) { @@ -2264,6 +2537,17 @@ sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg) cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd); break; + case SDIOH_CMD_11: /* Select card - Response R1 */ + sd_data(("%s: CMD%d\n", __FUNCTION__, cmd)); + cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48); + cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1); + cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1); + cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0); + cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL); + cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd); + break; + + case SDIOH_CMD_15: /* Set card to inactive state - Response None */ sd_data(("%s: CMD%d\n", __FUNCTION__, cmd)); cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_NONE); @@ -2312,7 +2596,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; @@ -2321,22 +2605,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); @@ -2438,6 +2746,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 && @@ -2506,7 +2815,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]) { @@ -2596,12 +2905,21 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n int_bit = SFIELD(0, INTSTAT_BUF_READ_READY, 1); else int_bit = SFIELD(0, INTSTAT_BUF_WRITE_READY, 1); - /* If not on, wait for it (or for xfer error) */ int_reg = sdstd_rreg16(sd, SD_IntrStatus); - if (!(int_reg & int_bit)) - int_reg = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, yield); - + if (!(int_reg & int_bit)) { + status = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, + yield, &int_reg); + switch (status) { + case -1: + sd_err(("%s: pio interrupted\n", __FUNCTION__)); + return ERROR; + case -2: + sd_err(("%s: pio timeout waiting for interrupt\n", + __FUNCTION__)); + return ERROR; + } + } /* Confirm we got the bit w/o error */ if (!(int_reg & int_bit) || GFIELD(int_reg, INTSTAT_ERROR_INT)) { sd_err(("%s: Error or timeout for Buf_%s_Ready: intStat: 0x%x " @@ -2609,13 +2927,13 @@ 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); } /* Clear Buf Ready bit */ sdstd_wreg16(sd, SD_IntrStatus, int_bit); - /* At this point we have Buffer Ready, write the data 4 bytes at a time */ for (words = blocksize/4; words; words--) { if (read) @@ -2625,10 +2943,6 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n data++; } - /* Handle < 4 bytes. wlc_pio.c currently (as of 12/20/05) truncates buflen - * to be evenly divisable by 4. However dongle passes arbitrary lengths, - * so handle it here - */ bytes = blocksize % 4; /* If no leftover bytes, go to next block */ @@ -2681,8 +2995,17 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n /* If not on, wait for it (or for xfer error) */ int_reg = sdstd_rreg16(sd, SD_IntrStatus); - if (!(int_reg & int_bit)) - int_reg = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, yield); + if (!(int_reg & int_bit)) { + status = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, yield, &int_reg); + switch (status) { + case -1: + sd_err(("%s: interrupted\n", __FUNCTION__)); + return ERROR; + case -2: + sd_err(("%s: timeout waiting for interrupt\n", __FUNCTION__)); + return ERROR; + } + } /* Check for any errors from the data phase */ if (sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg)) @@ -2697,6 +3020,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; } @@ -2714,6 +3038,7 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n sd_sync_dma(sd, read, nbytes); bcopy(sd->dma_buf, data, nbytes); } + return SUCCESS; } @@ -2744,7 +3069,8 @@ set_client_block_size(sdioh_info_t *sd, int func, int block_size) } /* Reset and re-initialize the device */ -int sdioh_sdio_reset(sdioh_info_t *si) +int +sdioh_sdio_reset(sdioh_info_t *si) { uint8 hreg; @@ -2767,17 +3093,214 @@ 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)) == NULL) { + + int alloced; + void *va; + + alloced = 0; + if ((va = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE, SD_PAGE_BITS, &alloced, + &sd->dma_start_phys, 0x12)) == 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 = 0; 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 = alloced; + 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_PAGE_BITS, &alloced, + &sd->adma2_dscr_start_phys, 0x12)) == 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 = alloced; + 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/src/bcmsdio/sys/bcmsdstd_linux.c b/src/bcmsdio/sys/bcmsdstd_linux.c index ef63163..a124d9a 100644 --- a/src/bcmsdio/sys/bcmsdstd_linux.c +++ b/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-2011, 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_linux.c,v 1.11.18.2 2008/05/28 18:36:56 Exp $ + * $Id: bcmsdstd_linux.c,v 1.14.2.8 2010-11-11 08:57:44 Exp $ */ #include <typedefs.h> @@ -41,12 +41,15 @@ struct sdos_info { wait_queue_head_t intr_wait_queue; }; +#define SDSTD_WAITBITS_TIMEOUT (5 * HZ) /* seconds * HZ */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define BLOCKABLE() (!in_atomic()) #else #define BLOCKABLE() (!in_interrupt()) #endif + /* Interrupt handler */ static irqreturn_t sdstd_isr(int irq, void *dev_id @@ -60,6 +63,7 @@ sdstd_isr(int irq, void *dev_id bool ours; sd = (sdioh_info_t *)dev_id; + sdos = (struct sdos_info *)sd->sdos_info; if (!sd->card_init_done) { sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); @@ -70,7 +74,7 @@ sdstd_isr(int irq, void *dev_id /* For local interrupts, wake the waiting process */ if (ours && sd->got_hcint) { sd_trace(("INTR->WAKE\n")); - sdos = (struct sdos_info *)sd->sdos_info; +/* sdos = (struct sdos_info *)sd->sdos_info; */ wake_up_interruptible(&sdos->intr_wait_queue); } return IRQ_RETVAL(ours); @@ -126,6 +130,7 @@ sdstd_osinit(sdioh_info_t *sd) return BCME_OK; } + void sdstd_osfree(sdioh_info_t *sd) { @@ -178,6 +183,7 @@ sdstd_lock(sdioh_info_t *sd) { ulong flags; struct sdos_info *sdos; + int wait_count = 0; sdos = (struct sdos_info *)sd->sdos_info; ASSERT(sdos); @@ -185,10 +191,17 @@ sdstd_lock(sdioh_info_t *sd) sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); spin_lock_irqsave(&sdos->lock, flags); - if (sd->lockcount) { - sd_err(("%s: Already locked!\n", __FUNCTION__)); - ASSERT(sd->lockcount == 0); + while (sd->lockcount) + { + spin_unlock_irqrestore(&sdos->lock, flags); + yield(); + spin_lock_irqsave(&sdos->lock, flags); + if (++wait_count == 10000) { + ASSERT(sd->lockcount == 0); + } } + if (wait_count) + printk("sdstd_lock: wait count = %d\n", wait_count); sdstd_devintr_off(sd); sd->lockcount++; spin_unlock_irqrestore(&sdos->lock, flags); @@ -214,10 +227,24 @@ sdstd_unlock(sdioh_info_t *sd) spin_unlock_irqrestore(&sdos->lock, flags); } -uint16 -sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield) +void +sdstd_waitlockfree(sdioh_info_t *sd) +{ + if (sd->lockcount) { + printk("wait lock free\n"); + while (sd->lockcount) + { + yield(); + } + } +} + +/* Returns 0 for success, -1 for interrupted, -2 for timeout */ +int +sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits) { struct sdos_info *sdos; + int rc = 0; sdos = (struct sdos_info *)sd->sdos_info; @@ -235,7 +262,15 @@ sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield) if (yield && BLOCKABLE()) { /* Enable interrupts, wait for the indication, then disable */ sdstd_intrs_on(sd, norm, err); - wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); + rc = wait_event_interruptible_timeout(sdos->intr_wait_queue, + (sd->got_hcint), + SDSTD_WAITBITS_TIMEOUT); + if (rc < 0) + rc = -1; /* interrupted */ + else if (rc == 0) + rc = -2; /* timeout */ + else + rc = 0; /* success */ sdstd_intrs_off(sd, norm, err); } else #endif /* BCMSDYIELD */ @@ -245,5 +280,7 @@ sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield) sd_trace(("%s: last_intrstatus 0x%04x\n", __FUNCTION__, sd->last_intrstatus)); - return sd->last_intrstatus; + *bits = sd->last_intrstatus; + + return rc; } diff --git a/src/branding.inc b/src/branding.inc index d38a2fd..a246d27 100644 --- a/src/branding.inc +++ b/src/branding.inc @@ -1,4 +1,4 @@ -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2011, 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/src/dhd/exe/GNUmakefile b/src/dhd/exe/GNUmakefile index b0a9cf8..0a5e442 100644 --- a/src/dhd/exe/GNUmakefile +++ b/src/dhd/exe/GNUmakefile @@ -1,15 +1,14 @@ # # GNUmakefile for dhd/exe -# (Basically a copy of wl/exe linux portion.) # -# Copyright (C) 1999-2009, Broadcom Corporation -# +# Copyright (C) 1999-2011, Broadcom Corporation +# # Unless you and Broadcom execute a separate written software license # agreement governing use of this software, this software is licensed to you # under the terms of the GNU General Public License version 2 (the "GPL"), # available at http://www.broadcom.com/licenses/GPLv2.php, with the # following added to such license: -# +# # As a special exception, the copyright holders of this software give you # permission to link this software with independent modules, and to copy and # distribute the resulting executable under terms of your choice, provided that @@ -17,23 +16,25 @@ # the license of that module. An independent module is a module which is not # derived from this software. The special exception does not apply to any # modifications of the software. -# +# # 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: GNUmakefile,v 1.9.24.4.16.5 2009/03/03 08:51:47 Exp $ +# $Id: GNUmakefile,v 1.25.4.3 2011-01-13 00:19:30 Exp $ -SRCBASE = ../.. +ifndef SRCBASE + SRCBASE = ../.. +endif UNAME = $(shell uname) -#----------------------------------------------------------- +#----------------------------------------------------------------- # Windows build # 1) windows, don't include Makerules due to all: conflict + ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) -SRCFILE = include ../../GNUmakefile.inc else # UNAME @@ -42,67 +43,63 @@ else # UNAME include $(SRCBASE)/Makerules + +#ifdef BCMWPA2 +CFLAGS += -DBCMWPA2 +#endif # Always include pktgen commands in the application CFLAGS += -DSDTEST +#ifdef WLCNT +CFLAGS += -DWLCNT +#endif + -#----------------------------------------------------------- +CFLAGS += -DWLBTAMP + +CFLAGS += -DDONGLEOVERLAYS + +#----------------------------------------------------------------- # Linux build # -ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linuxarm linuxarm_le android"),) +# This should be one of values recognized in src/Makerules +ifneq ($(findstring $(TARGETENV), "linux linuxmips linuxmips_be linux26mips linuxarm linuxarm_le android"),) + # $(TARGETARCH) is set based on TARGETENV in src/Makerules.* files -DHD_OBJS := dhdu.o dhdu_linux.o bcmutils.o miniopt.o +DHD_OBJS := dhdu.o dhdu_linux.o bcmutils.o bcmwifi.o miniopt.o DHD_EXE := dhd - +DHD_OBJS := $(DHD_OBJS:%.o=%.o) ifneq ($(findstring x86,$(TARGETARCH)),x86) DHD_EXE := $(DHD_EXE)$(TARGETARCH) DHD_OBJS := $(DHD_OBJS:%.o=$(TARGETARCH)/%.o) endif -# extra warnings -CFLAGS += -Wextra $(CUSTOM_FLAGS) +CFLAGS += -DWLPFN -DLINUX -g -I$(SRCBASE)/wl/exe vpath %.c $(SRCBASE)/shared +vpath %.c $(SRCBASE)/wl/exe all: $(DHD_EXE) -$(DHD_EXE): $(DHD_OBJS) - $(CC) $(LDFLAGS) -o $@ $^ - -$(TARGETARCH)/%.o: %.c - @mkdir -p $(TARGETARCH) - $(CC) -c $(CFLAGS) -o $@ $^ - clean: - @rm -rf $(TARGETARCH) - rm -f $(DHD_EXE) *.o - rm -rf build - -endif # linux - -#----------------------------------------------------------- -# MacOS -# -ifeq ($(TARGETENV), macos) -DHD_EXE := dhd_macos -BUILD := xcodebuild -PROJECT := dhd.xcodeproj -PROJTGT := dhd - -all: $(DHD_EXE) + rm -fr $(DHD_EXE) $(DHD_OBJS) $(TARGETARCH) -# Executable is located in build/Debug/dhd -dhd_macos: - $(BUILD) -project $(PROJECT) -target $(PROJTGT) -configuration Debug build +$(DHD_EXE): $(DHD_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ -clean: - rm -f $(DHD_EXE) *.o - rm -rf build +%.o: %.c + $(CC) -c $(CFLAGS) -DRWL_SOCKET -DRWL_WIFI -DRWL_DONGLE -o $@ $^ -endif # macos +ifneq ($(findstring x86, $(TARGETARCH)),x86) +$(TARGETARCH)/%.o: %.c + @mkdir -p $(TARGETARCH) + $(CC) -c $(CFLAGS) -I ../../include -DRWL_SOCKET -DRWL_WIFI -DRWL_DONGLE -o $@ $^ +endif .PHONY: all clean +endif # TARGETENV linux + endif # UNAME diff --git a/src/dhd/exe/dhdu.c b/src/dhd/exe/dhdu.c index fbe7ba2..929d6aa 100644 --- a/src/dhd/exe/dhdu.c +++ b/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-2011, 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,16 +21,17 @@ * 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.16.14 2009/09/28 23:29:58 Exp $ + * $Id: dhdu.c,v 1.88.2.19 2011-01-19 23:47:10 Exp $ */ -/* For backwards compatibility, the absense of the define 'BWL_NO_FILESYSTEM_SUPPORT' +/* For backwards compatibility, the absence of the define 'BWL_NO_FILESYSTEM_SUPPORT' * implies that a filesystem is supported. */ #if !defined(BWL_NO_FILESYSTEM_SUPPORT) #define BWL_FILESYSTEM_SUPPORT #endif +#define PROP_TXSTATUS #include <stdio.h> #include <stdlib.h> @@ -46,9 +47,10 @@ #include <bcmutils.h> #include <bcmendian.h> #include "dhdu.h" - - #include "miniopt.h" +#include <proto/bcmip.h> +#define IPV4_ADDR_LEN 4 +#include <proto/bt_amp_hci.h> #include <errno.h> @@ -71,9 +73,15 @@ 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_membytes, dhd_download, dhd_upload, dhd_vars, dhd_idleclock, dhd_idletime; +static cmd_func_t dhd_dma_mode; +static cmd_func_t dhd_membytes, dhd_download, dhd_dldn, + dhd_upload, dhd_vars, dhd_idleclock, dhd_idletime; static cmd_func_t dhd_logstamp; +#ifdef PROP_TXSTATUS +static cmd_func_t dhd_proptxstatusenable; +static cmd_func_t dhd_proptxstatusmode; +#endif static int dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr); static int dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len); @@ -87,7 +95,8 @@ static int file_size(char *fname); static int read_vars(char *fname, char *buf, int buf_maxlen); #endif - +static cmd_func_t wl_HCI_cmd; +static cmd_func_t wl_HCI_ACL_data; /* dword align allocation */ static union { @@ -147,8 +156,12 @@ cmd_t dhd_cmds[] = { "get/set maximum number of rx frames per scheduling"}, { "txminmax", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, "get/set maximum number of tx frames per scheduling while rx frames outstanding"}, + { "dconpoll", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set dongle console polling interval (ms)"}, { "dump", dhd_varstr, DHD_GET_VAR, -1, "dump information"}, + { "cons", dhd_varstr, -1, DHD_SET_VAR, + "send string to device console (sd only)"}, { "clearcounts", dhd_var_void, -1, DHD_SET_VAR, "reset the bus stats shown in the dhd dump"}, { "logdump", dhd_varstr, DHD_GET_VAR, -1, @@ -171,6 +184,9 @@ cmd_t dhd_cmds[] = { "\t--noreset do not reset SOCRAM core before download\n" "\t--norun do not start dongle CPU after download\n" "\tdefault <address> is 0\n"}, + { "dldn", dhd_dldn, -1, DHD_SET_VAR, + "download <binfile>\n" + "\tdownload file to specified dongle ram address 0\n"}, { "vars", dhd_vars, DHD_GET_VAR, DHD_SET_VAR, "vars [<file>]\n" "\toverride SPROM vars with <file> (before download)\n"}, @@ -209,6 +225,8 @@ cmd_t dhd_cmds[] = { "\t read up to <-c> pkts every <-f> ticks until <-t>\n" "\t total reads\n"}, #endif /* SDTEST */ + { "dngl_isolation", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set dongle isolation, so the dev could be disabled with out effecting the dongle state"}, { "sdreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR, "g/set sdpcmdev core register (f1) across SDIO (CMD53)"}, { "sbreg", dhd_sdreg, DHD_GET_VAR, DHD_SET_VAR, @@ -225,8 +243,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, @@ -257,10 +275,38 @@ cmd_t dhd_cmds[] = { "SDIO Device drive strength in milliamps. (0=tri-state, 1-12mA)"}, { "devreset", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, "Move device into or out of reset state (1/reset, or 0/operational)"}, - { "connstatus", dhd_varstr, DHD_GET_VAR, -1, - "get status of last connection attempt" }, { "ioctl_timeout", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, "IOCTL response timeout (milliseconds)."}, + { "HCI_cmd", wl_HCI_cmd, -1, DHD_SET_VAR, + "carries HCI commands to the driver\n" + "\tusage: dhd HCI_cmd <command> <args>\n" }, + { "HCI_ACL_data", wl_HCI_ACL_data, -1, DHD_SET_VAR, + "carries HCI ACL data packet to the driver\n" + "\tusage: dhd HCI_ACL_data <logical link handle> <data>\n" }, +#ifdef PROP_TXSTATUS + { "proptx", dhd_proptxstatusenable, DHD_GET_VAR, DHD_SET_VAR, + "enable/disable the proptxtstatus feature\n" + "0 - disabled\n" + "1 - enabled\n"}, + { "ptxmode", dhd_proptxstatusmode, DHD_GET_VAR, DHD_SET_VAR, + "set the proptxtstatus operation mode:\n" + "0 - Unsupported\n" + "1 - Use implied credit from a packet status\n" + "2 - Use explicit credit\n" }, +#endif + { "sd_uhsimode", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "g/set UHSI Mode"}, +#ifdef WLMEDIA_HTSF + { "pktdlystatsz", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "Specify the size of the delay statistics buffer\n" + "0 - disable"}, +#endif + { "hsicsleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "sleep/wake HSIC bus"}, + { "changemtu", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "change the size of the mtu during runtime <1500-1752> Bytes\n"}, + { "hsicautosleep", dhd_varint, DHD_GET_VAR, DHD_SET_VAR, + "Enable/Disable HSIC bus automatic sleep/resume feature"}, { NULL, NULL, 0, 0, NULL } }; @@ -406,6 +452,7 @@ dhd_list(void *dhd, cmd_t *garb, char **argv) printf("%s\n", buf+row*80); printf("\n"); + free(buf); return (0); } @@ -669,6 +716,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} }; @@ -683,7 +731,7 @@ dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv) { int ret; int argc; - char *endptr; + char *endptr = NULL; void *ptr = NULL; int func, size; @@ -698,7 +746,7 @@ dhd_sd_blocksize(void *dhd, cmd_t *cmd, char **argv) func = strtol(argv[1], &endptr, 0); if (*endptr != '\0') { - printf("Invaild function: %s\n", argv[1]); + printf("Invalid function: %s\n", argv[1]); return USAGE_ERROR; } @@ -762,6 +810,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) @@ -769,7 +867,7 @@ dhd_sdreg(void *dhd, cmd_t *cmd, char **argv) int ret; sdreg_t sdreg; uint argc; - char *ptr; + char *ptr = NULL; UNUSED_PARAMETER(cmd); @@ -991,7 +1089,7 @@ static int dhd_idletime(void *dhd, cmd_t *cmd, char **argv) { int32 idletime; - char *endptr; + char *endptr = NULL; int err = 0; if (argv[1]) { @@ -1040,7 +1138,7 @@ static int dhd_idleclock(void *dhd, cmd_t *cmd, char **argv) { int32 idleclock; - char *endptr; + char *endptr = NULL; int err = 0; if (argv[1]) { @@ -1331,7 +1429,6 @@ dhd_vars(void *dhd, cmd_t *cmd, char **argv) int ret; uint argc; char *bufp; - char *vname; UNUSED_PARAMETER(cmd); @@ -1354,7 +1451,9 @@ dhd_vars(void *dhd, cmd_t *cmd, char **argv) #if defined(BWL_FILESYSTEM_SUPPORT) case 1: /* set */ { + char *vname; uint nvram_len; + vname = argv[1]; bufp = buf; @@ -1440,6 +1539,40 @@ dhd_load_file_bytes(void *dhd, cmd_t *cmd, FILE *fp, int fsize, int start) } #endif /* BWL_FILESYSTEM_SUPPORT */ +#ifdef PROP_TXSTATUS +static int +dhd_proptxstatusenable(void *dhd, cmd_t *cmd, char **argv) +{ + int flag = 0xdead; + + if (argv[1]) { + flag = atoi(argv[1]); + dhd_iovar_setint(dhd, cmd->name, flag); + } + else { + dhd_iovar_getint(dhd, cmd->name, &flag); + printf("proptxstatus: %d\n", flag); + } + return 0; +} + +static int +dhd_proptxstatusmode(void *dhd, cmd_t *cmd, char **argv) +{ + int mode = 0xdead; + + if (argv[1]) { + mode = atoi(argv[1]); + dhd_iovar_setint(dhd, cmd->name, mode); + } + else { + dhd_iovar_getint(dhd, cmd->name, &mode); + printf("proptxstatusmode: %d\n", mode); + } + return 0; +} +#endif /* PROP_TXSTATUS */ + static int dhd_download(void *dhd, cmd_t *cmd, char **argv) { @@ -1453,18 +1586,18 @@ dhd_download(void *dhd, cmd_t *cmd, char **argv) uint32 start = 0; int ret = 0; int fsize; - FILE *fp = NULL; uint32 memsize; char *memszargs[] = { "memsize", NULL }; - char *bufp; - miniopt_t opts; int opt_err; uint nvram_len; struct trx_header trx_hdr; bool trx_file = FALSE; + bool overlays = FALSE; + + UNUSED_PARAMETER(cmd); /* Parse command-line options */ miniopt_init(&opts, "download", "", TRUE); @@ -1520,7 +1653,6 @@ dhd_download(void *dhd, cmd_t *cmd, char **argv) goto exit; } - /* validate file size compared to memory size */ if ((fsize = file_size(fname)) < 0) { ret = -1; @@ -1540,14 +1672,14 @@ dhd_download(void *dhd, cmd_t *cmd, char **argv) tmp_len = fread(&trx_hdr, sizeof(uint8), trx_hdr_len, fp); if (tmp_len == trx_hdr_len) { if (trx_hdr.magic == TRX_MAGIC) { - fprintf(stderr, "TRX file\n"); trx_file = TRUE; - /* trx header file format: image_size, rom_img_size, rom_load_adr */ - fprintf(stderr, "dongle RAM Image size %d\n", trx_hdr.offsets[0]); - fprintf(stderr, "dongle ROM Image size %d\n", trx_hdr.offsets[1]); - fprintf(stderr, "dongle ROM Loadaddr 0x%x\n", trx_hdr.offsets[2]); - fsize = trx_hdr.offsets[0] + trx_hdr.offsets[1]; - fprintf(stderr, "filesize is %d\n", fsize); + if (trx_hdr.flag_version & TRX_OVERLAYS) { + fprintf(stderr, "Image contains overlays but overlays " + "not supported by this command\n"); + ret = BCME_UNSUPPORTED; + goto exit; + } else { + } } else fseek(fp, 0, SEEK_SET); @@ -1563,12 +1695,15 @@ dhd_download(void *dhd, cmd_t *cmd, char **argv) memsize = *(uint32*)buf; +#ifdef PART_OF_RAM_AS_ROMSIM + /* only useful for cases where you want to sim some RAM as ROM */ if (memsize && ((uint32)fsize > memsize)) { fprintf(stderr, "%s: file %s too large (%d > %d)\n", __FUNCTION__, fname, fsize, memsize); ret = -1; goto exit; } +#endif /* PART_OF_RAM_AS_ROMSIM */ /* do the download reset if not suppressed */ if (reset) { @@ -1578,33 +1713,22 @@ dhd_download(void *dhd, cmd_t *cmd, char **argv) goto exit; } } + if (trx_file) fsize = trx_hdr.offsets[0]; + /* Load the ram image */ if (dhd_load_file_bytes(dhd, cmd, fp, fsize, start)) { fprintf(stderr, "%s: error loading the ramimage at addr 0x%x\n", - __FUNCTION__, start); - ret = -1; - goto exit; - } - if (trx_file) { - /* Load the rom library */ - start = trx_hdr.offsets[2]; - fsize = trx_hdr.offsets[1]; - - fprintf(stderr, "setting the maxsocram value 0x%x \n", start); - if (dhd_iovar_setint(dhd, "maxsocram", start)) { - fprintf(stderr, "%s: setting the maxram size to %d failed\n", - __FUNCTION__, start); - goto exit; - } + __FUNCTION__, start); + ret = -1; + goto exit; + } - if (dhd_load_file_bytes(dhd, cmd, fp, fsize, start)) { - fprintf(stderr, "%s: error loading the rom library at addr 0x%x\n", - __FUNCTION__, start); - goto exit; + if (trx_file) { + if (overlays) { + } else { } - } fclose(fp); @@ -1647,6 +1771,130 @@ exit: if (fp) fclose(fp); + + return ret; +#endif /* BWL_FILESYSTEM_SUPPORT */ +} + +static int +dhd_dldn(void *dhd, cmd_t *cmd, char **argv) +{ +#if !defined(BWL_FILESYSTEM_SUPPORT) + return (-1); +#else + char *fname = NULL; + uint32 start = 0; + int ret = 0; + int fsize; + int fd = 0; + + FILE *fp = NULL; + uint32 memsize; + + uint len; + uint8 memblock[MEMBLOCK]; + + miniopt_t opts; + int opt_err; + + UNUSED_PARAMETER(cmd); + + /* Parse command-line options */ + miniopt_init(&opts, "download", "", TRUE); + argv++; + + while ((opt_err = miniopt(&opts, argv)) != -1) { + if (opt_err == 1) { + fprintf(stderr, "download options error\n"); + ret = -1; + goto exit; + } + argv += opts.consumed; + + if (opts.positional) { + if (fname) { + fprintf(stderr, "extra positional arg, %s\n", + opts.valstr); + ret = -1; + goto exit; + } + if (!fname) + fname = opts.valstr; + } else { + fprintf(stderr, "unrecognized option %c\n", opts.opt); + ret = -1; + goto exit; + } + } + + fd = dhd_set(dhd, DHD_DLDN_ST, NULL, 0); + if (fd < 0) { + ret = -1; + goto exit; + } + + /* validate arguments */ + if (!fname) { + fprintf(stderr, "filename required\n"); + ret = -1; + goto exit; + } + + /* validate file size compared to memory size */ + if ((fsize = file_size(fname)) < 0) { + ret = -1; + goto exit; + } + + memsize = 393216; + + if (memsize && ((uint32)fsize > memsize)) { + fprintf(stderr, "%s: file %s too large (%d > %d)\n", + __FUNCTION__, fname, fsize, memsize); + ret = -1; + goto exit; + } + + /* read the file and push blocks down to memory */ + if ((fp = fopen(fname, "rb")) == NULL) { + fprintf(stderr, "%s: unable to open %s: %s\n", + __FUNCTION__, fname, strerror(errno)); + ret = -1; + goto exit; + } + + while ((len = fread(memblock, sizeof(uint8), MEMBLOCK, fp))) { + if (len < MEMBLOCK && !feof(fp)) { + fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname); + ret = -1; + goto exit; + } + + ret = dhd_set(dhd, DHD_DLDN_WRITE, memblock, len); + if (ret) { + fprintf(stderr, "%s: error %d on writing %d membytes at 0x%08x\n", + __FUNCTION__, ret, len, start); + goto exit; + } + + start += len; + } + + if (!feof(fp)) { + fprintf(stderr, "%s: error reading file %s\n", __FUNCTION__, fname); + ret = -1; + goto exit; + } + fclose(fp); + fp = NULL; + +exit: + if (fp) + fclose(fp); + + if (fd) + dhd_set(dhd, DHD_DLDN_END, NULL, 0); + return ret; #endif /* BWL_FILESYSTEM_SUPPORT */ } @@ -1784,7 +2032,7 @@ static int dhd_logstamp(void *dhd, cmd_t *cmd, char **argv) { int ret; - char *endptr; + char *endptr = NULL; uint argc; int valn[2] = {0, 0}; @@ -1821,7 +2069,7 @@ dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv) { int ret; sdreg_t sdreg; - char *endptr; + char *endptr = NULL; uint argc; void *ptr = NULL; @@ -1911,8 +2159,8 @@ static int dhd_do_msglevel(void *dhd, cmd_t *cmd, char **argv, dbg_msg_t *dbg_msg) { int ret, i; - uint val, last_val = 0, msglevel, msglevel_add = 0, msglevel_del = 0; - char *endptr; + uint val, last_val = 0, msglevel = 0, msglevel_add = 0, msglevel_del = 0; + char *endptr = NULL; if ((ret = dhd_iovar_getint(dhd, cmd->name, (int*)&msglevel)) < 0) return (ret); @@ -2024,7 +2272,7 @@ dhd_var_setint(void *dhd, cmd_t *cmd, char **argv) int32 val; int len; char *varname; - char *endptr; + char *endptr = NULL; char *p; if (cmd->set == -1) { @@ -2059,7 +2307,7 @@ dhd_var_setint(void *dhd, cmd_t *cmd, char **argv) p++; } - /* skip the null */ + /* skip the NUL */ p++; memcpy(p, &val, sizeof(uint)); @@ -2102,7 +2350,6 @@ dhd_var_getint(void *dhd, cmd_t *cmd, char **argv) { int err; int32 val; - if (cmd->get == -1) { printf("get not defined for %s\n", cmd->name); return COMMAND_ERROR; @@ -2138,6 +2385,7 @@ void dhd_printlasterror(void *dhd) { char *cmd[2] = {"bcmerrorstr"}; + if (dhd_var_get(dhd, NULL, cmd) != 0) { fprintf(stderr, "%s: \nError getting the last error\n", dhdu_av0); } else { @@ -2162,7 +2410,7 @@ dhd_var_getbuf(void *dhd, char *iovar, void *param, int param_len, void **bufptr memset(buf, 0, DHD_IOCTL_MAXLEN); strcpy(buf, iovar); - /* include the null */ + /* include the NUL */ len = strlen(iovar) + 1; if (param_len) @@ -2181,7 +2429,7 @@ dhd_var_setbuf(void *dhd, char *iovar, void *param, int param_len) memset(buf, 0, DHD_IOCTL_MAXLEN); strcpy(buf, iovar); - /* include the null */ + /* include the NUL */ len = strlen(iovar) + 1; if (param_len) @@ -2283,7 +2531,169 @@ dhd_varstr(void *dhd, cmd_t *cmd, char **argv) return (0); } else { str = *argv; - /* str length includes the NUL */ + /* iovar buffer length includes NUL */ return dhd_var_setbuf(dhd, cmd->name, str, strlen(str) + 1); } } + + + +#define MATCH_OP(op, opstr) (strlen(op) == strlen(opstr) && strncmp(op, opstr, strlen(op)) == 0) + +static int +wl_HCI_cmd(void *wl, cmd_t *cmd, char **argv) +{ + union { + char buf[HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE]; + uint32 alignme; + } cbuf; + amp_hci_cmd_t *cpkt = (amp_hci_cmd_t *)&cbuf.buf[0]; + + char *op; + uint8 plen; + + UNUSED_PARAMETER(cmd); + + if (!*++argv) + return USAGE_ERROR; + + /* recognize and encode operations */ + op = *argv++; + if (MATCH_OP(op, "Read_Link_Quality")) { + cpkt->opcode = HCI_Read_Link_Quality; + } else if (MATCH_OP(op, "Read_Local_AMP_Info")) { + cpkt->opcode = HCI_Read_Local_AMP_Info; + } else if (MATCH_OP(op, "Read_Local_AMP_ASSOC")) { + cpkt->opcode = HCI_Read_Local_AMP_ASSOC; + } else if (MATCH_OP(op, "Write_Remote_AMP_ASSOC")) { + cpkt->opcode = HCI_Write_Remote_AMP_ASSOC; + } else if (MATCH_OP(op, "Create_Physical_Link")) { + cpkt->opcode = HCI_Create_Physical_Link; + } else if (MATCH_OP(op, "Accept_Physical_Link_Request")) { + cpkt->opcode = HCI_Accept_Physical_Link_Request; + } else if (MATCH_OP(op, "Disconnect_Physical_Link")) { + cpkt->opcode = HCI_Disconnect_Physical_Link; + } else if (MATCH_OP(op, "Create_Logical_Link")) { + cpkt->opcode = HCI_Create_Logical_Link; + } else if (MATCH_OP(op, "Accept_Logical_Link")) { + cpkt->opcode = HCI_Accept_Logical_Link; + } else if (MATCH_OP(op, "Disconnect_Logical_Link")) { + cpkt->opcode = HCI_Disconnect_Logical_Link; + } else if (MATCH_OP(op, "Logical_Link_Cancel")) { + cpkt->opcode = HCI_Logical_Link_Cancel; + } else if (MATCH_OP(op, "Short_Range_Mode")) { + cpkt->opcode = HCI_Short_Range_Mode; + } else if (MATCH_OP(op, "Read_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Connection_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Connection_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Read_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Write_Link_Supervision_Timeout")) { + cpkt->opcode = HCI_Write_Link_Supervision_Timeout; + } else if (MATCH_OP(op, "Reset")) { + cpkt->opcode = HCI_Reset; + } else if (MATCH_OP(op, "Enhanced_Flush")) { + cpkt->opcode = HCI_Enhanced_Flush; + } else if (MATCH_OP(op, "Read_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Read_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Write_Best_Effort_Flush_Timeout")) { + cpkt->opcode = HCI_Write_Best_Effort_Flush_Timeout; + } else if (MATCH_OP(op, "Read_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Read_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Write_Logical_Link_Accept_Timeout")) { + cpkt->opcode = HCI_Write_Logical_Link_Accept_Timeout; + } else if (MATCH_OP(op, "Read_Buffer_Size")) { + cpkt->opcode = HCI_Read_Buffer_Size; + } else if (MATCH_OP(op, "Read_Data_Block_Size")) { + cpkt->opcode = HCI_Read_Data_Block_Size; + } else if (MATCH_OP(op, "Set_Event_Mask_Page_2")) { + cpkt->opcode = HCI_Set_Event_Mask_Page_2; + } else if (MATCH_OP(op, "Flow_Spec_Modify")) { + cpkt->opcode = HCI_Flow_Spec_Modify; + } else if (MATCH_OP(op, "Read_Local_Version_Info")) { + cpkt->opcode = HCI_Read_Local_Version_Info; + } else if (MATCH_OP(op, "Read_Local_Supported_Commands")) { + cpkt->opcode = HCI_Read_Local_Supported_Commands; + } else if (MATCH_OP(op, "Read_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Read_Failed_Contact_Counter; + } else if (MATCH_OP(op, "Reset_Failed_Contact_Counter")) { + cpkt->opcode = HCI_Reset_Failed_Contact_Counter; + } else { + printf("unsupported HCI command: %s\n", op); + return (-1); + } + + plen = 0; + while (*argv && (plen < HCI_CMD_DATA_SIZE)) { + cpkt->parms[plen++] = (uint8)strtol(*argv++, NULL, 0); + } + cpkt->plen = plen; + + return dhd_var_setbuf(wl, cmd->name, cpkt, HCI_CMD_PREAMBLE_SIZE + plen); +} + +static int +wl_HCI_ACL_data(void *wl, cmd_t *cmd, char **argv) +{ + /* Align struct. Also declare static so that large array isn't allocated + * from the stack. + */ + static union { + uint8 buf[HCI_ACL_DATA_PREAMBLE_SIZE + 2048]; + uint32 alignme; + } g_hci_dbuf; + + amp_hci_ACL_data_t *dpkt = (amp_hci_ACL_data_t *)&g_hci_dbuf.buf[0]; + uint16 dlen; + + if (!*++argv) + return USAGE_ERROR; + + /* get logical link handle */ + dpkt->handle = (HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS); + dpkt->handle |= (uint16)strtol(*argv++, NULL, 0); + + /* get data */ + dlen = 0; + while (*argv && (dlen < 2048)) { + dpkt->data[dlen++] = (uint8)strtol(*argv++, NULL, 0); + } + dpkt->dlen = dlen; + + return dhd_var_setbuf(wl, cmd->name, dpkt, HCI_ACL_DATA_PREAMBLE_SIZE + dlen); +} + +/* These two utility functions are used by dhdu_linux.c + * The code is taken from wlu.c. + */ +int +dhd_atoip(const char *a, struct ipv4_addr *n) +{ + char *c; + int i = 0; + + for (;;) { + n->addr[i++] = (uint8)strtoul(a, &c, 0); + if (*c++ != '.' || i == IPV4_ADDR_LEN) + break; + a = c; + } + return (i == IPV4_ADDR_LEN); +} + +int +dhd_ether_atoe(const char *a, struct ether_addr *n) +{ + char *c; + int i = 0; + + memset(n, 0, ETHER_ADDR_LEN); + for (;;) { + n->octet[i++] = (uint8)strtoul(a, &c, 16); + if (!*c++ || i == ETHER_ADDR_LEN) + break; + a = c; + } + return (i == ETHER_ADDR_LEN); +} diff --git a/src/dhd/exe/dhdu.h b/src/dhd/exe/dhdu.h index 9a45a76..82a925a 100644 --- a/src/dhd/exe/dhdu.h +++ b/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-2011, 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.h,v 1.3.10.2.28.1 2008/10/25 00:31:00 Exp $ + * $Id: dhdu.h,v 1.7 2009-05-22 19:23:29 Exp $ */ #ifndef _dhdu_h_ @@ -47,6 +47,10 @@ extern void dhd_printint(int val); /* check driver version */ extern int dhd_check(void *dhd); +/* utility functions */ +struct ipv4_addr; +int dhd_ether_atoe(const char *a, struct ether_addr *n); +int dhd_atoip(const char *a, struct ipv4_addr *n); /* useful macros */ #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) diff --git a/src/dhd/exe/dhdu_cmd.h b/src/dhd/exe/dhdu_cmd.h index 1d6622b..fbf231d 100644 --- a/src/dhd/exe/dhdu_cmd.h +++ b/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-2011, 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_cmd.h,v 1.3.102.2 2008/05/07 00:19:34 Exp $ + * $Id: dhdu_cmd.h,v 1.6 2008-06-05 00:36:42 Exp $ */ #ifndef _dhdu_cmd_h_ @@ -43,6 +43,11 @@ struct cmd { extern cmd_t dhd_cmds[]; extern cmd_t dhd_varcmd; +/* Special set cmds to do download via dev node interface if present */ +#define DHD_DLDN_ST 0x400 +#define DHD_DLDN_WRITE (DHD_DLDN_ST + 1) +#define DHD_DLDN_END (DHD_DLDN_ST + 2) + /* per-port ioctl handlers */ extern int dhd_get(void *dhd, int cmd, void *buf, int len); extern int dhd_set(void *dhd, int cmd, void *buf, int len); diff --git a/src/dhd/exe/dhdu_common.h b/src/dhd/exe/dhdu_common.h new file mode 100644 index 0000000..988cd37 --- /dev/null +++ b/src/dhd/exe/dhdu_common.h @@ -0,0 +1,53 @@ +/* + * Linux port of dhd command line utility, hacked from wl utility. + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: dhdu_common.h,v 1.4.34.1 2011-02-05 00:43:28 Exp $ + */ + +/* Common header file for dhdu_linux.c and dhdu_ndis.c */ + +#ifndef _dhdu_common_h +#define _dhdu_common_h + +/* DHD utility function declarations */ +extern int dhd_check(void *dhd); +extern int dhd_atoip(const char *a, struct ipv4_addr *n); +extern int dhd_option(char ***pargv, char **pifname, int *phelp); +void dhd_usage(cmd_t *port_cmds); + +/* Remote DHD declarations */ +int remote_type = NO_REMOTE; +extern char *g_rwl_buf_mac; +extern char* g_rwl_device_name_serial; +unsigned short g_rwl_servport; +char *g_rwl_servIP = NULL; +unsigned short defined_debug = DEBUG_ERR | DEBUG_INFO; + + +static int process_args(struct ifreq* ifr, char **argv); + + +#define dtoh32(i) i +#define dtoh16(i) i + +#endif /* _dhdu_common_h_ */ diff --git a/src/dhd/exe/dhdu_linux.c b/src/dhd/exe/dhdu_linux.c index 2f7407a..65d036d 100644 --- a/src/dhd/exe/dhdu_linux.c +++ b/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-2011, 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_linux.c,v 1.3.10.2.16.2 2008/12/19 05:19:25 Exp $ + * $Id: dhdu_linux.c,v 1.16.2.2 2010-12-16 08:12:11 Exp $ */ #include <stdio.h> @@ -30,26 +30,56 @@ #include <ctype.h> #include <string.h> #include <errno.h> -#ifndef TARGETENV_android -#include <error.h> -#endif /* TARGETENV_android */ #include <sys/types.h> +#include <sys/wait.h> #include <sys/socket.h> +#include <proto/ethernet.h> +#include <proto/bcmip.h> +#include <arpa/inet.h> #include <sys/ioctl.h> #include <net/if.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> +#ifndef TARGETENV_android +#include <error.h> typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; +#endif /* TARGETENV_android */ #include <linux/sockios.h> +#include <linux/types.h> #include <linux/ethtool.h> #include <typedefs.h> +#include <signal.h> #include <dhdioctl.h> +#include <wlioctl.h> +#include <bcmcdc.h> +#include <bcmutils.h> #include "dhdu.h" +#include "wlu_remote.h" +#include <netdb.h> +#include <dhdioctl.h> +#include "dhdu_common.h" -#define DEV_TYPE_LEN 4 /* length for devtype 'dhd' */ +char *av0; +static int rwl_os_type = LINUX_OS; +/* Search the dhd_cmds table for a matching command name. + * Return the matching command or NULL if no match found. + */ +static cmd_t * +dhd_find_cmd(char* name) +{ + cmd_t *cmd = NULL; + /* search the dhd_cmds for a matching name */ + for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, name); cmd++); + if (cmd->name == NULL) + cmd = NULL; + return cmd; +} static void syserr(char *s) @@ -59,6 +89,9 @@ syserr(char *s) exit(errno); } +/* This function is called by ioctl_setinformation_fe or ioctl_queryinformation_fe + * for executing remote commands or local commands + */ static int dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) { @@ -66,6 +99,19 @@ dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) dhd_ioctl_t ioc; int ret = 0; int s; + /* By default try to execute wl commands */ + int driver_magic = WLC_IOCTL_MAGIC; + int get_magic = WLC_GET_MAGIC; + + /* For local dhd commands execute dhd. For wifi transport we still + * execute wl commands. + */ + if (remote_type == NO_REMOTE && strncmp (buf, RWL_WIFI_ACTION_CMD, + strlen(RWL_WIFI_ACTION_CMD)) && strncmp(buf, RWL_WIFI_GET_ACTION_CMD, + strlen(RWL_WIFI_GET_ACTION_CMD))) { + driver_magic = DHD_IOCTL_MAGIC; + get_magic = DHD_GET_MAGIC; + } /* open socket to kernel */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) @@ -76,10 +122,11 @@ dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) ioc.buf = buf; ioc.len = len; ioc.set = set; - ioc.driver = DHD_IOCTL_MAGIC; + ioc.driver = driver_magic; ifr->ifr_data = (caddr_t) &ioc; + if ((ret = ioctl(s, SIOCDEVPRIVATE, ifr)) < 0) { - if (cmd != DHD_GET_MAGIC) { + if (cmd != get_magic) { ret = IOCTL_ERROR; } } @@ -89,8 +136,21 @@ dhd_ioctl(void *dhd, int cmd, void *buf, int len, bool set) return ret; } +/* This function is called in wlu_pipe.c remote_wifi_ser_init() to execute + * the initial set of wl commands for wifi transport (e.g slow_timer, fast_timer etc) + */ +int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set) +{ + return dhd_ioctl(wl, cmd, buf, len, set); /* Call actual wl_ioctl here: Shubhro */ +} + +/* Search if dhd adapter or wl adapter is present + * This is called by dhd_find to check if it supports wl or dhd + * The reason for checking wl adapter is that we can still send remote dhd commands over + * wifi transport. + */ static int -dhd_get_dev_type(char *name, void *buf, int len) +dhd_get_dev_type(char *name, void *buf, char *type) { int s; int ret; @@ -104,7 +164,8 @@ dhd_get_dev_type(char *name, void *buf, int len) /* get device type */ memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GDRVINFO; - strcpy(info.driver, "?dhd"); + strcpy(info.driver, "?"); + strcat(info.driver, type); ifr.ifr_data = (caddr_t)&info; strncpy(ifr.ifr_name, name, IFNAMSIZ); if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { @@ -116,34 +177,105 @@ dhd_get_dev_type(char *name, void *buf, int len) *(char *)buf = '\0'; } else - strncpy(buf, info.driver, len); + strcpy(buf, info.driver); close(s); return ret; } +/* dhd_get/dhd_set is called by several functions in dhdu.c. This used to call dhd_ioctl + * directly. However now we need to execute the dhd commands remotely. + * So we make use of wl pipes to execute this. + * wl_get or wl_set functions also check if it is a local command hence they in turn + * call dhd_ioctl if required. Name wl_get/wl_set is retained because these functions are + * also called by wlu_pipe.c wlu_client_shared.c + */ int dhd_get(void *dhd, int cmd, void *buf, int len) { - return dhd_ioctl(dhd, cmd, buf, len, FALSE); + return wl_get(dhd, cmd, buf, len); } +/* + * To use /dev/node interface: + * 1. mknod /dev/hnd0 c 248 0 + * 2. chmod 777 /dev/hnd0 + */ +#define NODE "/dev/hnd0" + int dhd_set(void *dhd, int cmd, void *buf, int len) { - return dhd_ioctl(dhd, cmd, buf, len, TRUE); + static int dnode = -1; + + switch (cmd) { + case DHD_DLDN_ST: + if (dnode == -1) + dnode = open(NODE, O_RDWR); + else + fprintf(stderr, "devnode already opened!\n"); + + return dnode; + break; + case DHD_DLDN_WRITE: + if (dnode > 0) + return write(dnode, buf, len); + break; + case DHD_DLDN_END: + if (dnode > 0) + return close(dnode); + break; + default: + return wl_set(dhd, cmd, buf, len); + + } + + return -1; } +/* Verify the wl adapter found. + * This is called by dhd_find to check if it supports wl + * The reason for checking wl adapter is that we can still send remote dhd commands over + * wifi transport. The function is copied from wlu.c. + */ +int +wl_check(void *wl) +{ + int ret; + int val = 0; + + if (!dhd_check (wl)) + return 0; + + /* + * If dhd_check() fails then go for a regular wl driver verification + */ + if ((ret = wl_get(wl, WLC_GET_MAGIC, &val, sizeof(int))) < 0) + return ret; + if (val != WLC_IOCTL_MAGIC) + return BCME_ERROR; + if ((ret = wl_get(wl, WLC_GET_VERSION, &val, sizeof(int))) < 0) + return ret; + if (val > WLC_IOCTL_VERSION) { + fprintf(stderr, "Version mismatch, please upgrade\n"); + return BCME_ERROR; + } + return 0; +} +/* Search and verify the request type of adapter (wl or dhd) + * This is called by main before executing local dhd commands + * or sending remote dhd commands over wifi transport + */ void -dhd_find(struct ifreq *ifr) +dhd_find(struct ifreq *ifr, char *type) { char proc_net_dev[] = "/proc/net/dev"; FILE *fp; - char buf[1000], *c, *name; - char dev_type[DEV_TYPE_LEN]; + static char buf[400]; + char *c, *name; + char dev_type[32]; ifr->ifr_name[0] = '\0'; - /* eat first two lines */ if (!(fp = fopen(proc_net_dev, "r")) || !fgets(buf, sizeof(buf), fp) || @@ -157,81 +289,349 @@ dhd_find(struct ifreq *ifr) if (!(name = strsep(&c, ":"))) continue; strncpy(ifr->ifr_name, name, IFNAMSIZ); - if (dhd_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && - !strncmp(dev_type, "dhd", 3)) - if (dhd_check((void *)ifr) == 0) + if (dhd_get_dev_type(name, dev_type, type) >= 0 && + !strncmp(dev_type, type, strlen(dev_type) - 1)) + { + if (!wl_check((void*)ifr)) break; + } ifr->ifr_name[0] = '\0'; } fclose(fp); } +/* This function is called by wl_get to execute either local dhd command + * or send a dhd command over wl transport + */ +static int +ioctl_queryinformation_fe(void *wl, int cmd, void* input_buf, int *input_len) +{ +#if defined(BCMRWL) + if (remote_type == NO_REMOTE) { +#endif /* defined(BCMRWL) */ + return dhd_ioctl(wl, cmd, input_buf, *input_len, FALSE); +#if defined(BCMRWL) + } else { + return rwl_queryinformation_fe(wl, cmd, input_buf, + (unsigned long*)input_len, 0, RDHD_GET_IOCTL); + } +#endif /* defined(BCMRWL) */ +} + +/* This function is called by wl_set to execute either local dhd command + * or send a dhd command over wl transport + */ +static int +ioctl_setinformation_fe(void *wl, int cmd, void* buf, int *len) +{ +#if defined(BCMRWL) + if (remote_type == NO_REMOTE) { +#endif /* defined(BCMRWL) */ + return dhd_ioctl(wl, cmd, buf, *len, TRUE); +#if defined(BCMRWL) + } else { + return rwl_setinformation_fe(wl, cmd, buf, (unsigned long*)len, 0, RDHD_SET_IOCTL); + + } +#endif /* defined(BCMRWL) */ +} + +/* The function is replica of wl_get in wlu_linux.c. Optimize when we have some + * common code between wlu_linux.c and dhdu_linux.c + */ +int +wl_get(void *wl, int cmd, void *buf, int len) +{ + int error = BCME_OK; + /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */ + if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) { + error = (int)ioctl_queryinformation_fe(wl, WL_OID_BASE + cmd, buf, &len); + } else { + error = (int)ioctl_queryinformation_fe(wl, cmd, buf, &len); + } + if (error == SERIAL_PORT_ERR) + return SERIAL_PORT_ERR; + + if (error != 0) + return IOCTL_ERROR; + + return error; +} + +/* The function is replica of wl_set in wlu_linux.c. Optimize when we have some + * common code between wlu_linux.c and dhdu_linux.c + */ +int +wl_set(void *wl, int cmd, void *buf, int len) +{ + int error = BCME_OK; + + /* For RWL: When interfacing to a Windows client, need t add in OID_BASE */ + if ((rwl_os_type == WIN32_OS) && (remote_type != NO_REMOTE)) { + error = (int)ioctl_setinformation_fe(wl, WL_OID_BASE + cmd, buf, &len); + } else { + error = (int)ioctl_setinformation_fe(wl, cmd, buf, &len); + } + + if (error == SERIAL_PORT_ERR) + return SERIAL_PORT_ERR; + if (error != 0) { + return IOCTL_ERROR; + } + return error; +} +/* Main client function + * The code is mostly from wlu_linux.c. This function takes care of executing remote dhd commands + * along with the local dhd commands now. + */ int main(int argc, char **argv) { struct ifreq ifr; - cmd_t *cmd = NULL; - int err = 0; char *ifname = NULL; + int err = 0; int help = 0; int status = CMD_DHD; - +#if defined(BCMRWL) + void* serialHandle = NULL; + struct ipv4_addr temp; +#endif /* defined(BCMRWL) */ UNUSED_PARAMETER(argc); - dhdu_av0 = argv[0]; - + av0 = argv[0]; memset(&ifr, 0, sizeof(ifr)); + argv++; + + if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { + if (ifname) + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + } +#if defined(BCMRWL) + /* Linux client looking for a Win32 server */ + if (*argv && strncmp (*argv, "--wince", strlen(*argv)) == 0) { + rwl_os_type = WIN32_OS; + argv++; + } + + /* RWL socket transport Usage: --socket ipaddr [port num] */ + if (*argv && strncmp (*argv, "--socket", strlen(*argv)) == 0) { + argv++; - for (++argv; *argv;) { + remote_type = REMOTE_SOCKET; + + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } - /* command option */ + if (!dhd_atoip(*argv, &temp)) { + rwl_usage(remote_type); + return err; + } + g_rwl_servIP = *argv; + argv++; + + g_rwl_servport = DEFAULT_SERVER_PORT; + if ((*argv) && isdigit(**argv)) { + g_rwl_servport = atoi(*argv); + argv++; + } + } + + /* RWL from system serial port on client to uart dongle port on server */ + /* Usage: --dongle /dev/ttyS0 */ + if (*argv && strncmp (*argv, "--dongle", strlen(*argv)) == 0) { + argv++; + remote_type = REMOTE_DONGLE; + + if (!(*argv)) { + rwl_usage(remote_type); + return err; + } + g_rwl_device_name_serial = *argv; + argv++; + if ((serialHandle = rwl_open_pipe(remote_type, "\0", 0, 0)) == NULL) { + DPRINT_ERR(ERR, "serial device open error\r\n"); + return BCME_ERROR; + } + ifr = (*(struct ifreq *)serialHandle); + } + + /* RWL over wifi. Usage: --wifi mac_address */ + if (*argv && strncmp (*argv, "--wifi", strlen(*argv)) == 0) { + argv++; + remote_type = NO_REMOTE; + if (!ifr.ifr_name[0]) + { + dhd_find(&ifr, "wl"); + } + /* validate the interface */ + if (!ifr.ifr_name[0] || wl_check((void*)&ifr)) { + fprintf(stderr, "%s: wl driver adapter not found\n", av0); + exit(1); + } + remote_type = REMOTE_WIFI; + + if (argc < 4) { + rwl_usage(remote_type); + return err; + } + /* copy server mac address to local buffer for later use by findserver cmd */ + if (!dhd_ether_atoe(*argv, (struct ether_addr *)g_rwl_buf_mac)) { + fprintf(stderr, + "could not parse as an ethernet MAC address\n"); + return FAIL; + } + argv++; + } +#endif /* defined(BCMRWL) */ + + /* Process for local dhd */ + if (remote_type == NO_REMOTE) { + err = process_args(&ifr, argv); + return err; + } + + if (*argv) { + err = process_args(&ifr, argv); + if ((err == SERIAL_PORT_ERR) && (remote_type == REMOTE_DONGLE)) { + DPRINT_ERR(ERR, "\n Retry again\n"); + err = process_args((struct ifreq*)&ifr, argv); + } + return err; + } +#if defined(BCMRWL) + rwl_usage(remote_type); + + if (remote_type == REMOTE_DONGLE) + rwl_close_pipe(remote_type, (void*)&ifr); +#endif /* defined(BCMRWL) */ + return err; +} +/* + * Function called for 'local' execution and for 'remote' non-interactive session + * (shell cmd, wl cmd) .The code is mostly from wlu_linux.c. This code can be + * common to wlu_linux.c and dhdu_linux.c + */ +static int +process_args(struct ifreq* ifr, char **argv) +{ + char *ifname = NULL; + int help = 0; + int status = 0; + int err = BCME_OK; + cmd_t *cmd = NULL; + while (*argv) { +#if defined(BCMRWL) + if ((strcmp (*argv, "sh") == 0) && (remote_type != NO_REMOTE)) { + argv++; /* Get the shell command */ + if (*argv) { + /* Register handler in case of shell command only */ + signal(SIGINT, ctrlc_handler); + err = rwl_shell_cmd_proc((void*)ifr, argv, SHELL_CMD); + } else { + DPRINT_ERR(ERR, + "Enter the shell command (e.g ls(Linux) or dir(Win CE) \n"); + err = BCME_ERROR; + } + return err; + } +#endif /* defined(BCMRWL) */ if ((status = dhd_option(&argv, &ifname, &help)) == CMD_OPT) { if (help) break; - if (ifname) { - if (strlen(ifname) > IFNAMSIZ) { - fprintf(stderr, "%s: interface name too long\n", dhdu_av0); - break; - } - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - } + if (ifname) + strncpy(ifr->ifr_name, ifname, IFNAMSIZ); continue; } - /* parse error */ else if (status == CMD_ERR) - break; + break; + + if (remote_type == NO_REMOTE) { + /* use default interface */ + if (!ifr->ifr_name[0]) + dhd_find(ifr, "dhd"); + /* validate the interface */ + if (!ifr->ifr_name[0] || dhd_check((void *)ifr)) { + if (strcmp("dldn", *argv) != 0) { + fprintf(stderr, "%s: dhd driver adapter not found\n", av0); + exit(BCME_ERROR); + } + } - /* use default if no interface specified */ - if (!*ifr.ifr_name) - dhd_find(&ifr); - /* validate the interface */ - if (!*ifr.ifr_name || dhd_check((void *)&ifr)) { - fprintf(stderr, "%s: dhd driver adapter not found\n", dhdu_av0); - exit(1); } - /* search for command */ - for (cmd = dhd_cmds; cmd->name && strcmp(cmd->name, *argv); cmd++); - - /* defaults to using the set_var and get_var commands */ - if (cmd->name == NULL) + cmd = dhd_find_cmd(*argv); + /* if not found, use default set_var and get_var commands */ + if (!cmd) { cmd = &dhd_varcmd; + } /* do command */ - if (cmd->name) - err = (*cmd->func)((void *)&ifr, cmd, argv); + err = (*cmd->func)((void *) ifr, cmd, argv); break; - } - - /* In case of COMMAND_ERROR, command has already printed an error message */ - if (!cmd) + } /* while loop end */ + + /* provide for help on a particular command */ + if (help && *argv) { + cmd = dhd_find_cmd(*argv); + if (cmd) { + dhd_cmd_usage(cmd); + } else { + DPRINT_ERR(ERR, "%s: Unrecognized command \"%s\", type -h for help\n", + av0, *argv); + } + } else if (!cmd) dhd_usage(NULL); else if (err == USAGE_ERROR) dhd_cmd_usage(cmd); else if (err == IOCTL_ERROR) - dhd_printlasterror((void *)&ifr); + dhd_printlasterror((void *) ifr); return err; } + +int +rwl_shell_createproc(void *wl) +{ + UNUSED_PARAMETER(wl); + return fork(); +} + +void +rwl_shell_killproc(int pid) +{ + kill(pid, SIGKILL); +} + +#ifdef RWL_SOCKET +/* validate hostname/ip given by the client */ +int +validate_server_address() +{ + struct hostent *he; + struct ipv4_addr temp; + + if (!dhd_atoip(g_rwl_servIP, &temp)) { + /* Wrong IP address format check for hostname */ + if ((he = gethostbyname(g_rwl_servIP)) != NULL) { + if (!dhd_atoip(*he->h_addr_list, &temp)) { + g_rwl_servIP = inet_ntoa(*(struct in_addr *)*he->h_addr_list); + if (g_rwl_servIP == NULL) { + DPRINT_ERR(ERR, "Error at inet_ntoa \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Error in IP address \n"); + return FAIL; + } + } else { + DPRINT_ERR(ERR, "Enter correct IP address/hostname format\n"); + return FAIL; + } + } + return SUCCESS; +} +#endif /* RWL_SOCKET */ diff --git a/src/dhd/linux/Makefile b/src/dhd/linux/Makefile index 741eedf..3f1a820 100644 --- a/src/dhd/linux/Makefile +++ b/src/dhd/linux/Makefile @@ -1,7 +1,7 @@ # GNU Makefile for Broadcom Dongle Host Driver # -# Copyright (C) 1999-2009, Broadcom Corporation +# Copyright (C) 1999-2011, 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,9 +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: Makefile,v 1.55.2.6.2.10.12.25 2009/10/08 01:29:00 Exp $ +# $Id: Makefile,v 1.93.6.24 2011-02-10 02:31:08 Exp $ # +# Although 32ON64 flag is supposed to be passed from caller, set it +# if not set by caller on certain kernels and platforms +ifeq ($(shell uname -m),x86_64) + ifneq ($(findstring x86_64,$(LINUXVER)),x86_64) + export 32ON64=1 + # $(warning Passing 32ON64 flag to force 32bit driver for $(LINUXVER)) + endif # LINUXVER +endif # CURPROC + # Try a couple of places for LINUXDIR if not specified ifeq ($(LINUXDIR),) ifeq ($(LINUXVER),) @@ -57,6 +66,9 @@ endif # LINUXVER # check if 2.4 kernel or 2.5+ kernel BCM_KVER:=$(shell echo $(LINUXVER) | cut -c1-3 | sed 's/2\.[56]/2\.6/') +LINUX_MAJOR=$(shell echo $(LINUXVER) | cut -c3-3) +LINUX_MINOR=$(shell echo $(LINUXVER) | cut -c5-6) + # Allow CROSS_COMPILE to specify compiler base CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld @@ -67,20 +79,23 @@ 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)/wl/phy ## Initialize DFLAGS DFLAGS := +CFILES := # basic options (defines in DFLAGS, includes in IFLAGS) -DFLAGS += -DLINUX -DSRCBASE=\"$(SRCBASE)\" -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 -DBCMWAPI_WPI -DFLAGS += -DUNRELEASEDCHIP +DFLAGS += -DLINUX -DSRCBASE=\"$(SRCBASE)\" -DBCMDRIVER -DBCMDONGLEHOST +DFLAGS += -DUNRELEASEDCHIP -DBCMDMA32 +DFLAGS += -DWLBTAMP +DFLAGS += -DBCMFILEIMAGE ifeq ($(BCMQT),1) DFLAGS += -DBCMSLTGT -DBCMQT endif ifeq ($(WLTEST),1) - DFLAGS += -DWLTEST -DIOCTL_RESP_TIMEOUT=20000 + DFLAGS += -DIOCTL_RESP_TIMEOUT=20000 DFLAGS += -DDHD_SPROM endif @@ -113,6 +128,7 @@ IFLAGS += -I$(SRCBASE)/shared IFLAGS += -I$(SRCBASE)/dhd/sys IFLAGS += -I$(SRCBASE)/dongle IFLAGS += -I$(SRCBASE)/wl/sys +IFLAGS += -I$(SRCBASE)/wl/phy ifneq ($(wildcard $(LINUXDIR)/.config),) include $(LINUXDIR)/.config @@ -122,22 +138,22 @@ CONFIG_WIRELESS_EXT=y DFLAGS += -DCONFIG_WIRELESS_EXT endif -ifeq ($(CONFIG_MMC_MSM7X00A),y) +ifeq ($(CONFIG_MMC_MSM7X00A),y) DFLAGS += -Dlinux -DFLAGS += -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 -DDHD_FIRSTREAD=64 -endif +DFLAGS += -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 -DDHD_FIRSTREAD=64 +endif WFLAGS := -Wall -Wstrict-prototypes ifeq (,$(findstring 2.4.18,$(LINUXVER))) WFLAGS += -Werror endif -CFILES:= dhd_linux.c linux_osl.c bcmutils.c dhd_common.c dhd_custom_gpio.c -CFILES += siutils.c sbutils.c aiutils.c hndpmu.c +CFILES += dhd_linux.c linux_osl.c bcmutils.c bcmevent.c dhd_common.c dhd_custom_gpio.c +CFILES += siutils.c sbutils.c aiutils.c hndpmu.c dhd_bta.c # threading options -ifneq ($(findstring -nothread-,-$(TARGET)-),) -DFLAGS += -UDHDTHREAD +ifeq ($(findstring -nothread-,-$(TARGET)-),) +DFLAGS += -DDHDTHREAD endif # Building gpl provides thread prioritization @@ -146,6 +162,12 @@ CFILES += dhd_linux_sched.c DFLAGS += -DDHD_GPL -DDHD_SCHED endif +# Building hsic for 43239, 43236 and 4330 +ifneq ($(findstring -hsic-,-$(TARGET)-),) +DFLAGS += -DEXTENDED_VID_PID=' { USB_DEVICE(0x0a5c, 0xbd1b) }, \ + { USB_DEVICE(0x0a5c, 0xbd17) }, \ + { USB_DEVICE(0x0a5c, 0xbd19) }' +endif ifeq ($(WLTEST),1) CFILES += bcmsrom.c bcmotp.c endif @@ -165,6 +187,14 @@ ifneq ($(findstring -debug-,-$(TARGET)-),) DFLAGS += -DDHD_DEBUG -DSDTEST endif +# enable queuing in host +ifneq ($(findstring -sdstd-,-$(TARGET)-),) +DFLAGS += -DPROP_TXSTATUS +ifneq ($(findstring -dbgwlfc-,-$(TARGET)-),) +DFLAGS += -DPROP_TXSTATUS_DEBUG +endif +endif + # Make big-endian a separate option ifneq ($(findstring -be-,-$(TARGET)-),) DFLAGS += -DIL_BIGENDIAN @@ -173,7 +203,7 @@ endif ifneq ($(findstring -dnglimage-,-$(TARGET)-),) ## Embeddable dongle image name DNGL_IMAGE_NAME ?= 4325b0/sdio-g-cdc-reclaim-idsup-wme -DFLAGS += -DBCMEMBEDIMAGE -DIMAGE_NAME="$(DNGL_IMAGE_NAME)" +DFLAGS += -DBCM_DNGL_EMBEDIMAGE -DIMAGE_NAME="$(DNGL_IMAGE_NAME)" IFLAGS += -I$(SRCBASE)/dongle/rte/wl/builds/$(DNGL_IMAGE_NAME) endif @@ -181,45 +211,133 @@ ifneq ($(findstring -cdc-,-$(TARGET)-),) DFLAGS += -DBDC -DTOE DFLAGS += -DDHD_BCMEVENTS -DSHOW_EVENTS CFILES += dhd_cdc.c -ifneq ($(findstring -apsta-,-$(TARGET)-),) -DFLAGS += -DAP -DAPSTA_PINGTEST -endif endif ifneq ($(findstring -rndis-,-$(TARGET)-),) DFLAGS += -DRNDIS CFILES += dhd_rndis.c endif +ifneq ($(findstring -dbususb-,-$(TARGET)-),) +DFLAGS += -DBCMDHDUSB -DBCMDBUS +CFILES += dbus.c dbus_usb.c dbus_usb_linux.c +endif +ifneq ($(findstring -dbususb-dnglimage-,-$(TARGET)-),) +DFLAGS += -DBCMDHDUSB -DBCMDBUS +DFLAGS += -DBCM_DNGL_EMBEDIMAGE +CFILES += dbus.c dbus_usb.c dbus_usb_linux.c +endif ifneq ($(findstring -usb-,-$(TARGET)-),) -DFLAGS += -DBCMDHDUSB -CFILES += dhd_usb_linux.c +DFLAGS += -DBCMDHDUSB -DBCMDBUS +CFILES += dbus.c dbus_usb.c dbus_usb_linux.c +else +# no usb overlay support for now +DFLAGS += -DDONGLEOVERLAYS +endif +ifneq ($(findstring -dbus-,$(TARGET)-),) +DFLAGS += -DBCMDBUS -DBCMSDIO +CFILES += dbus.c dbus_sdio.c dbus_sdio_linux.c +endif +ifneq ($(findstring -dbussdstd-,$(TARGET)-),) +DFLAGS += -DBCMSDIO -DBCMSDIOH_STD +CFILES += bcmsdh.c bcmsdstd.c bcmsdstd_linux.c bcmsdh_linux.c +DFLAGS += -DBCMDBUS +CFILES += dbus.c dbus_sdio.c dbus_sdio_linux.c endif ifneq ($(findstring -sdio-,-$(TARGET)-),) DFLAGS += -DBCMSDIO CFILES += dhd_sdio.c endif +ifneq ($(findstring -sdbcm-,$(TARGET)-),) +DFLAGS += -DBCMSDIO -DBCMSDIOH_BCM -DTESTDONGLE +CFILES += dhd_sdio.c bcmsdh.c bcmsdbrcm.c bcmsdbrcm_linux.c bcmsdh_linux.c hnddma.c +endif ifneq ($(findstring -sdstd-,$(TARGET)-),) DFLAGS += -DBCMSDIO -DBCMSDIOH_STD CFILES += dhd_sdio.c bcmsdh.c bcmsdstd.c bcmsdstd_linux.c bcmsdh_linux.c +ifneq ($(findstring -hc3-,$(TARGET)-),) +DFLAGS += -DSDHOST3=1 endif -ifneq ($(findstring -oob-,-$(TARGET)-),) +endif +ifneq ($(findstring -nexus-,-$(TARGET)-),) +DFLAGS += -Dlinux +DFLAGS += -DOEM_ANDROID +DFLAGS += -DBCMDBG +DFLAGS += -DDHD_USE_STATIC_BUF +DFLAGS += -DCONFIG_MACH_MAHIMAHI +DFLAGS += -DCUSTOM_OOB_GPIO_NUM=299 DFLAGS += -DOOB_INTR_ONLY +DFLAGS += -DMMC_SDIO_ABORT +DFLAGS += -DCONFIG_FIRST_SCAN +DFLAGS += -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS +ifeq ("$(LINUX_MINOR)", "35") +$(warning : extra defintion for Android Gingerbread **) +DFLAGS += -DHW_OOB +#DFLAGS += -DCSCAN +endif +ifeq ("$(LINUX_MINOR)", "38") +$(warning : extra defintion for Android Gingerbread **) +DFLAGS += -DHW_OOB +#DFLAGS += -DCSCAN +endif +CFILES += dhd_sdio.c bcmsdh_sdmmc.c bcmsdh.c bcmsdh_linux.c bcmsdh_sdmmc_linux.c + +ifneq ($(findstring -cfg80211-,-$(TARGET)-),) +ifndef COMPAT_WIRELESS +ifneq ("$(LINUX_MINOR)", "38") +DFLAGS += -DANDROID_WIRELESS_PATCH +COMPAT_WIRELESS=/projects/hnd/tools/linuxwireless/compat-wireless +export COMPAT_WIRELESS else -ifneq ($(findstring -sdmmc-,-$(TARGET)-),) -DFLAGS += -DSDIO_ISR_THREAD +DFLAGS += -DNEW_COMPAT_WIRELESS endif endif + +CFILES += wl_cfg80211.c +DFLAGS += -DWL_CFG80211 +DFLAGS += -DWLP2P +CFILES += wl_cfgp2p.c +endif + +else +ifneq ($(findstring -oob-,-$(TARGET)-),) +DFLAGS += -DOOB_INTR_ONLY +DFLAGS += -DHW_OOB +DFLAGS += -DMMC_SDIO_ABORT +else ifneq ($(findstring -sdmmc-,-$(TARGET)-),) -DFLAGS += -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS +DFLAGS += -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS -DSDIO_ISR_THREAD CFILES += dhd_sdio.c bcmsdh_sdmmc.c bcmsdh.c bcmsdh_linux.c bcmsdh_sdmmc_linux.c endif +endif +endif + + + +ifneq ($(findstring -sdiofd-,-$(TARGET)-),) +DFLAGS += -DBCMSDIO -DBCMSDH_FD +CFILES += dhd_sdio.c bcmsdh_fd.c bcmsdh.c bcmsdh_linux.c bcmsdh_fd_linux.c +endif ifneq ($(findstring -sdspi-,$(TARGET)-),) DFLAGS += -DBCMSDIO -DBCMSDIOH_SPI -DTESTDONGLE # -DBCMSDYIELD CFILES += dhd_sdio.c bcmsdh.c bcmsdspi.c bcmsdspi_linux.c bcmsdh_linux.c endif +ifneq ($(findstring -gspi-,$(TARGET)-),) +DFLAGS += -DBCMSDIO -DBCMSDIOH_SPI -DTESTDONGLE -DBCMSPI +CFILES += dhd_sdio.c bcmsdh.c bcmspibrcm.c bcmsdspi_linux.c bcmsdh_linux.c +endif +ifneq ($(findstring -gspibcm,$(TARGET)-),) +DFLAGS += -DBCMSDIO -DBCMSDIOH_SPI -DTESTDONGLE -DBCMSPI +CFILES += dhd_sdio.c bcmsdh.c bcmgspi.c bcmsdbrcm_linux.c bcmsdh_linux.c hnddma.c +endif ifneq ($(findstring -pci,$(TARGET)-),) CFILES += bcmpcispi.c endif +ifneq ($(findstring -cheetah,$(TARGET)-),) +CFILES += bcmcheetahspi.c +endif +ifneq ($(findstring -u2c,$(TARGET)-),) +CFILES += bcmu2cspi.c +endif ifneq ($(findstring -sdext-,$(TARGET)-),) DFLAGS += -DBCMSDIO -DTESTDONGLE CFILES += dhd_sdio.c @@ -228,13 +346,24 @@ ifneq ($(findstring -intc1,$(shell echo $(LINUXVER))),) DFLAGS += -DSANDGATE2G endif -CFLAGS += -fshort-wchar $(DFLAGS) $(WFLAGS) $(IFLAGS) $(CUSTOM_FLAGS) +ifneq ($(findstring -n2dbg-,$(TARGET)-),) +DFLAGS += -DWLMEDIA_HTSF -DHOST_TS +endif + +#ifdef WIFI_ACT_FRAME +DFLAGS += -DWIFI_ACT_FRAME +#endif + +CFLAGS += -fshort-wchar $(DFLAGS) $(WFLAGS) $(IFLAGS) LDFLAGS := -r 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 @@ -252,12 +381,26 @@ else endif TARGETS := \ - dhd-cdc-usb dhd-cdc-sdstd \ - dhd-cdc-sdspi-pci dhd-cdc-sdmmc-gpl dhd-cdc-sdmmc-oob-gpl + dhd-cdc-usb dhd-cdc-dbususb dhd-cdc-dbususb-dnglimage dhd-cdc-sdio dhd-cdc-dbus dhd-cdc-sdbcm dhd-cdc-sdstd \ + dhd-cdc-dbussdstd dhd-cdc-sdspi-pci dhd-cdc-sdspi-cheetah dhd-cdc-sdspi-u2c dhd-cdc-sdmmc-nexus-gpl dhd-cdc-sdmmc-nexus-cfg80211-gpl\ + dhd-cdc-sdstd-nothread dhd-cdc-sdmmc-gpl \ + dhd-cdc-usb-gpl dhd-cdc-usb-hsic-gpl dhd-cdc-usb-hsic-padwar-gpl +TARGETS += dhd-cdc-usb-gpl-apsta +TARGETS += dhd-cdc-sdstd-apsta TARGETS += \ - dhd-cdc-sdio-dnglimage dhd-cdc-sdspi-pci-dnglimage \ - dhd-cdc-gspi-pci + dhd-cdc-sdio-dnglimage dhd-cdc-sdbcm-dnglimage \ + dhd-cdc-sdstd-dnglimage dhd-cdc-dbussdstd-dnglimage \ + dhd-cdc-dbus-dnglimage dhd-cdc-sdspi-pci-dnglimage \ + dhd-cdc-sdspi-cheetah-dnglimage dhd-cdc-gspi-pci \ + dhd-cdc-gspibcm \ + dhd-cdc-sdstd-hc3 \ + dhd-cdc-sdstd-n2dbg \ + dhd-cdc-sdstd-n2dbg-debug-nothread \ + dhd-cdc-sdstd-debug-nothread \ + dhd-cdc-sdstd-largemtu \ + dhd-cdc-sdstd-debug-largemtu + #ifdef RNDIS TARGETS += dhd-rndis-usb #endif @@ -297,7 +440,7 @@ 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 endif diff --git a/src/dhd/linux/makefile.26 b/src/dhd/linux/makefile.26 index aadd42e..41cc145 100644 --- a/src/dhd/linux/makefile.26 +++ b/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-2011, 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,8 +22,20 @@ # 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.26,v 1.1.144.1 2008/05/07 22:53:44 Exp $ +# $Id: makefile.26,v 1.2.50.3 2011-02-07 23:29:49 Exp $ +ifdef COMPAT_WIRELESS +NOSTDINC_FLAGS := -I$(COMPAT_WIRELESS)/include/ \ + -include $(COMPAT_WIRELESS)/include/linux/compat-2.6.h +endif + +ifneq ($(findstring -nexus-,-$(TARGET)-),) + +obj-m += bcm4329.o +bcm4329-objs = $(DHDOFILES) + +else obj-m += dhd.o dhd-objs = $(DHDOFILES) +endif EXTRA_CFLAGS = $(DHDCFLAGS) diff --git a/src/dhd/sys/dhd.h b/src/dhd/sys/dhd.h index fac2897..961a66d 100644 --- a/src/dhd/sys/dhd.h +++ b/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-2011, 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.28.36 2009/10/07 19:57:16 Exp $ + * $Id: dhd.h,v 1.60.4.17 2011-01-09 08:11:56 Exp $ */ /**************** @@ -34,7 +34,9 @@ #ifndef _dhd_h_ #define _dhd_h_ -#if defined(LINUX) +#if defined(CHROMIUMOS_COMPAT_WIRELESS) +#include <linux/sched.h> +#endif #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -46,32 +48,21 @@ #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 EINVAL 3 -#define EIO 4 -#define ETIMEDOUT 5 -#define ERESTARTSYS 6 -#endif /* LINUX */ + +#define ALL_INTERFACES 0xff #include <wlioctl.h> -#ifdef NDIS60 -#include <wdf.h> -#include <WdfMiniport.h> -#endif /* NDIS60 */ /* Forward decls */ struct dhd_bus; struct dhd_prot; struct dhd_info; +struct dhd_cmn; /* The level of bus communication with the dongle */ enum dhd_bus_state { @@ -89,9 +80,22 @@ enum dhd_bus_wake_state { WAKE_LOCK_TMOUT, WAKE_LOCK_WATCHDOG, WAKE_LOCK_LINK_DOWN_TMOUT, + WAKE_LOCK_PNO_FIND_TMOUT, + WAKE_LOCK_SOFTAP_SET, + WAKE_LOCK_SOFTAP_STOP, + WAKE_LOCK_SOFTAP_START, + WAKE_LOCK_SOFTAP_THREAD, WAKE_LOCK_MAX }; - +enum dhd_prealloc_index { + DHD_PREALLOC_PROT = 0, + DHD_PREALLOC_RXBUF, + DHD_PREALLOC_DATABUF, + DHD_PREALLOC_OSL_BUF +}; +#ifdef DHD_USE_STATIC_BUF +extern void * dhd_os_prealloc(int section, unsigned long size); +#endif /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ @@ -99,6 +103,7 @@ typedef struct dhd_pub { struct dhd_bus *bus; /* Bus module handle */ struct dhd_prot *prot; /* Protocol module handle */ struct dhd_info *info; /* Info module handle */ + struct dhd_cmn *cmn; /* dhd_common module handle */ /* Internal dhd items */ bool up; /* Driver up/down (to OS) */ @@ -129,9 +134,11 @@ typedef struct dhd_pub { ulong rx_ctlerrs; /* Errors in processing rx control frames */ ulong rx_dropped; /* Packets dropped locally (no memory) */ ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ + ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ + ulong fc_packets; /* Number of flow control pkts recvd */ /* Last error return */ int bcmerror; @@ -140,33 +147,55 @@ typedef struct dhd_pub { /* Last error from dongle */ int dongle_error; - uint8 country_code[WLC_CNTRY_BUF_SZ]; + /* Suspend disable flag and "in suspend" flag */ + int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ + int in_suspend; /* flag set to 1 when early suspend called */ +#ifdef PNO_SUPPORT + int pno_enable; /* pno status : "1" is pno enable */ +#endif /* PNO_SUPPORT */ + int dtim_skip; /* dtim skip , default 0 means wake each dtim */ + + /* Pkt filter defination */ + char * pktfilter[100]; + int pktfilter_count; + + wl_country_t dhd_cspec; /* Current Locale info */ + char eventmask[WL_EVENTING_MASK_LEN]; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - struct wake_lock wakelock[WAKE_LOCK_MAX]; + struct wake_lock wakelock[WAKE_LOCK_MAX]; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ + struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ +#endif + + uint16 maxdatablks; +#ifdef PROP_TXSTATUS + int wlfc_enabled; + void* wlfc_state; +#endif + bool dongle_isolation; - +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ +#endif } dhd_pub_t; -#ifdef NDIS60 - -typedef struct _wdf_device_info { +typedef struct dhd_cmn { + osl_t *osh; /* OSL handle */ dhd_pub_t *dhd; -} wdf_device_info_t; - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) - +} dhd_cmn_t; -#endif /* NDIS60 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); #define _DHD_PM_RESUME_WAIT(a, b) do {\ int retry = 0; \ + smp_mb(); \ while (dhd_mmc_suspend && retry++ != b) { \ - wait_event_timeout(a, FALSE, HZ/100); \ + wait_event_interruptible_timeout(a, FALSE, HZ/100); \ } \ } while (0) #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) @@ -176,10 +205,10 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9; \ - while ((exp) && (countdown >= 10)) { \ - wait_event_timeout(a, FALSE, HZ/100); \ - countdown -= 10; \ + uint countdown = (us) + 9999; \ + while ((exp) && (countdown >= 10000)) { \ + wait_event_interruptible_timeout(a, FALSE, HZ/100); \ + countdown -= 10000; \ } \ } while (0) @@ -201,48 +230,79 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) } while (0) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - - -inline static void WAKE_LOCK_INIT(dhd_pub_t * dhdp, int index, char * y) +#ifndef DHDTHREAD +#undef SPINWAIT_SLEEP +#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) +#endif /* DHDTHREAD */ +#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 MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) { -#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) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_init(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } -inline static void WAKE_LOCK(dhd_pub_t * dhdp, int index) +inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) { -#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) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_lock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } -inline static void WAKE_UNLOCK(dhd_pub_t * dhdp, int index) +inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) { -#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) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_unlock(&dhdp->wl_softap_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } -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) */ -} +#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) +#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) +#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) +#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub) dhd_os_wake_lock_timeout_enable(pub) + +extern void dhd_os_start_lock(dhd_pub_t *pub); +extern void dhd_os_start_unlock(dhd_pub_t *pub); + +extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub); +extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); -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; uint8 action; + uint8 flags; + uint8 bssidx; + uint8 is_AP; } dhd_if_event_t; +typedef enum dhd_attach_states +{ + DHD_ATTACH_STATE_INIT = 0x0, + DHD_ATTACH_STATE_NET_ALLOC = 0x1, + DHD_ATTACH_STATE_DHD_ALLOC = 0x2, + DHD_ATTACH_STATE_ADD_IF = 0x4, + DHD_ATTACH_STATE_PROT_ATTACH = 0x8, + DHD_ATTACH_STATE_WL_ATTACH = 0x10, + DHD_ATTACH_STATE_THREADS_CREATED = 0x20, + DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, + DHD_ATTACH_STATE_CFG80211 = 0x80, + DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, + DHD_ATTACH_STATE_DONE = 0x200 +} dhd_attach_states_t; + +/* Value -1 means we are unsuccessful in creating the kthread. */ +#define DHD_PID_KT_INVALID -1 +/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ +#define DHD_PID_KT_TL_INVALID -2 + /* * Exported from dhd OS modules (dhd_linux/dhd_ndis) */ @@ -261,12 +321,15 @@ extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); /* Indication from bus module regarding removal/absence of dongle */ extern void dhd_detach(dhd_pub_t *dhdp); +extern void dhd_free(dhd_pub_t *dhdp); /* Indication from bus module to change flow-control state */ extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); +extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); + /* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt); +extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); /* Return pointer to interface name */ extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); @@ -277,9 +340,6 @@ extern void dhd_sched_dpc(dhd_pub_t *dhdp); /* Notify tx completion */ extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); -/* Query ioctl */ -extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); - /* OS independent layer functions */ extern int dhd_os_proto_block(dhd_pub_t * pub); extern int dhd_os_proto_unblock(dhd_pub_t * pub); @@ -299,12 +359,24 @@ extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_customer_gpio_wlan_ctrl(int onoff); +extern int dhd_custom_get_mac_address(unsigned char *buf); extern 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); +#ifdef DHD_DEBUG +extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); +#endif /* DHD_DEBUG */ #if defined(OOB_INTR_ONLY) -extern int dhd_customer_oob_irq_map(void); +extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); #endif /* defined(OOB_INTR_ONLY) */ +extern void dhd_os_sdtxlock(dhd_pub_t * pub); +extern void dhd_os_sdtxunlock(dhd_pub_t * pub); +#if defined(DHDTHREAD) +struct task_struct; +struct sched_param; int setScheduler(struct task_struct *p, int policy, struct sched_param *param); +#endif /* DHDTHREAD && DHD_GPL */ typedef struct { uint32 limit; /* Expiration time (usec) */ @@ -317,27 +389,41 @@ extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); extern int dhd_timeout_expired(dhd_timeout_t *tmo); extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -extern int wl_host_event(struct dhd_info *dhd, int *idx, void *pktdata, -wl_event_msg_t *, void **data_ptr); +extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx); +extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, + wl_event_msg_t *, void **data_ptr); extern void wl_event_to_host_order(wl_event_msg_t * evt); -extern void dhd_common_init(void); +extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); +extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, + int ifindex); + +extern struct dhd_cmn *dhd_common_init(osl_t *osh); +extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn); -extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr); +extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, + char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); extern void dhd_del_if(struct dhd_info *dhd, int ifidx); -/* Send pakcet to dongle via data channel */ +extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); +extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); + +extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); +extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); + + +/* Send packet to dongle via data channel */ extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); -/* Send event to host */ /* send up locally generated event */ extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); +/* Send event to host */ extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); 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 int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); +extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); typedef enum cust_gpio_modes { @@ -347,20 +433,48 @@ typedef enum cust_gpio_modes { WLAN_POWER_OFF } cust_gpio_modes_t; - +extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); +extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); /* * Insmod parameters for debug/test */ -/* Watchdog timer frequency */ +/* Watchdog timer interval */ extern uint dhd_watchdog_ms; +#if defined(DHD_DEBUG) +/* Console output poll interval */ +extern uint dhd_console_ms; +extern uint wl_msg_level; +#endif /* defined(DHD_DEBUG) */ + /* Use interrupts */ extern uint dhd_intr; /* Use polling */ extern uint dhd_poll; +/* ARP offload agent mode */ +extern uint dhd_arp_mode; + +/* ARP offload enable */ +extern uint dhd_arp_enable; + +/* Pkt filte enable control */ +extern uint dhd_pkt_filter_enable; + +/* Pkt filter init setup */ +extern uint dhd_pkt_filter_init; + +/* Pkt filter mode control */ +extern uint dhd_master_mode; + +/* Roaming mode control */ +extern uint dhd_roam_disable; + +/* Roaming mode control */ +extern uint dhd_radio_up; + /* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ extern int dhd_idletime; #define DHD_IDLETIME_TICKS 1 @@ -386,13 +500,145 @@ extern uint dhd_pktgen_len; extern char fw_path[MOD_PARAM_PATHLEN]; extern char nv_path[MOD_PARAM_PATHLEN]; +#ifdef SOFTAP +extern char fw_path2[MOD_PARAM_PATHLEN]; +#endif + /* For supporting multiple interfaces */ #define DHD_MAX_IFS 16 #define DHD_DEL_IF -0xe #define DHD_BAD_IF -0xf -#ifdef APSTA_PINGTEST -#define MAX_GUEST 8 +#ifdef PROP_TXSTATUS +/* Please be mindful that total pkttag space is 32 octets only */ +typedef struct dhd_pkttag { + /* + b[11 ] - 1 = this packet was sent in response to one time packet request, + do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. + b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] + b[9 ] - 1 = packet is host->firmware (transmit direction) + - 0 = packet received from firmware (firmware->host) + b[8 ] - 1 = packet was sent due to credit_request (pspoll), + packet does not count against FIFO credit. + - 0 = normal transaction, packet counts against FIFO credit + b[7 ] - 1 = AP, 0 = STA + b[6:4] - AC FIFO number + b[3:0] - interface index + */ + uint16 if_flags; + /* destination MAC address for this packet so that not every + module needs to open the packet to find this + */ + uint8 dstn_ether[ETHER_ADDR_LEN]; + /* + This 32-bit goes from host to device for every packet. + */ + uint32 htod_tag; + /* bus specific stuff */ + union { + struct { + void* stuff; + uint32 thing1; + uint32 thing2; + } sd; + struct { + void* bus; + void* urb; + } usb; + } bus_specific; +} dhd_pkttag_t; + +#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) +#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) + +#define DHD_PKTTAG_IFMASK 0xf +#define DHD_PKTTAG_IFTYPE_MASK 0x1 +#define DHD_PKTTAG_IFTYPE_SHIFT 7 +#define DHD_PKTTAG_FIFO_MASK 0x7 +#define DHD_PKTTAG_FIFO_SHIFT 4 + +#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 +#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 + +#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 +#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 + +#define DHD_PKTTAG_PKTDIR_MASK 0x1 +#define DHD_PKTTAG_PKTDIR_SHIFT 9 + +#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 +#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 + +#define DHD_PKTTAG_INVALID_FIFOID 0x7 + +#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ + (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) +#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) + +#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK) +#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK) + +#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ + (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) +#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) + +#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ + (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) +#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) + +#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ + (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) +#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) + +#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ + (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) +#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) + +#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ + (((dhd_pkttag_t*)(tag))->if_flags & \ + ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ + (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) +#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ + DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) + +#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ + (dstn_MAC_ea), ETHER_ADDR_LEN) +#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether + +typedef int (*f_commitpkt_t)(void* ctx, void* p); +int dhd_wlfc_enable(dhd_pub_t *dhd); +int dhd_wlfc_interface_event(struct dhd_info *, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); +int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); +int dhd_wlfc_event(struct dhd_info *dhd); +int dhd_os_wlfc_block(dhd_pub_t *pub); +int dhd_os_wlfc_unblock(dhd_pub_t *pub); + +#ifdef PROP_TXSTATUS_DEBUG +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) +#else +#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) +#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) #endif +#endif /* PROP_TXSTATUS */ + +extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); +extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); + #endif /* _dhd_h_ */ diff --git a/src/dhd/sys/dhd_bta.c b/src/dhd/sys/dhd_bta.c new file mode 100644 index 0000000..6b782ea --- /dev/null +++ b/src/dhd/sys/dhd_bta.c @@ -0,0 +1,335 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: dhd_bta.c,v 1.10.4.2 2010-12-22 23:47:23 Exp $ + */ + +#include <typedefs.h> +#include <osl.h> +#include <bcmcdc.h> +#include <bcmutils.h> +#include <bcmendian.h> +#include <proto/802.11.h> +#include <proto/802.11_bta.h> +#include <proto/bt_amp_hci.h> +#include <dngl_stats.h> +#include <dhd.h> +#include <dhd_bus.h> +#include <dhd_proto.h> +#include <dhdioctl.h> +#include <dhd_dbg.h> + +#include <dhd_bta.h> + + +#ifdef SEND_HCI_CMD_VIA_IOCTL +#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE + +/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; + uint len = sizeof(buf); + wl_ioctl_t ioc; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) + return BCME_BADLEN; + + if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) + return BCME_BADLEN; + + len = bcm_mkiovar("HCI_cmd", + (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); + + + memset(&ioc, 0, sizeof(ioc)); + + ioc.cmd = WLC_SET_VAR; + ioc.buf = buf; + ioc.len = len; + ioc.set = TRUE; + + return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); +} +#else /* !SEND_HCI_CMD_VIA_IOCTL */ + +static void +dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) +{ + int prec; + struct pktq *q; + uint count = 0; + + q = dhd_bus_txq(pub->bus); + if (q == NULL) + return; + + DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); + + dhd_os_sdlock_txq(pub); + + /* Walk through the txq and toss all HCI ACL data packets */ + PKTQ_PREC_ITER(q, prec) { + void *head_pkt = NULL; + + while (pktq_ppeek(q, prec) != head_pkt) { + void *pkt = pktq_pdeq(q, prec); + int ifidx; + + PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); + dhd_prot_hdrpull(pub, &ifidx, pkt); + + if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { + struct ether_header *eh = + (struct ether_header *)PKTDATA(pub->osh, pkt); + + if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { + struct dot11_llc_snap_header *lsh = + (struct dot11_llc_snap_header *)&eh[1]; + + if (bcmp(lsh, BT_SIG_SNAP_MPROT, + DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && + ntoh16(lsh->type) == BTA_PROT_L2CAP) { + amp_hci_ACL_data_t *ACL_data = + (amp_hci_ACL_data_t *)&lsh[1]; + uint16 handle = ltoh16(ACL_data->handle); + + if (HCI_ACL_DATA_HANDLE(handle) == llh) { + PKTFREE(pub->osh, pkt, TRUE); + count ++; + continue; + } + } + } + } + + dhd_prot_hdrpush(pub, ifidx, pkt); + PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); + + if (head_pkt == NULL) + head_pkt = pkt; + pktq_penq(q, prec, pkt); + } + } + + dhd_os_sdunlock_txq(pub); + + DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); +} + +/* Handle HCI cmd locally. + * Return 0: continue to send the cmd across SDIO + * < 0: stop, fail + * > 0: stop, succuess + */ +static int +_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) +{ + int status = 0; + + switch (ltoh16_ua((uint8 *)&cmd->opcode)) { + case HCI_Enhanced_Flush: { + eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; + dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); + break; + } + default: + break; + } + + return status; +} + +/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ +int +dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) +{ + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + int status; + + if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); + return BCME_BADLEN; + } + + if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { + DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", + len, cmd_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_docmd: out of memory\n")); + return BCME_NOMEM; + } + + + /* intercept and handle the HCI cmd locally */ + if ((status = _dhd_bta_docmd(pub, cmd)) > 0) + return 0; + else if (status < 0) + return status; + + /* copy in HCI cmd */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(cmd, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + ETHER_SET_LOCALADDR(eh->ether_dhost); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = 0; + + return dhd_sendpkt(pub, 0, p); +} +#endif /* !SEND_HCI_CMD_VIA_IOCTL */ + +/* Send HCI ACL data to dongle via data channel */ +int +dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) +{ + amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; + osl_t *osh = pub->osh; + uint len; + void *p; + + if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { + DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); + return BCME_BADLEN; + } + + if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { + DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", + len, data_len)); + /* return BCME_BADLEN; */ + } + + p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); + if (p == NULL) { + DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); + return BCME_NOMEM; + } + + + /* copy in HCI ACL data header and HCI ACL data */ + PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); + bcopy(data, PKTDATA(osh, p), len); + + /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ + PKTPUSH(osh, p, RFC1042_HDR_LEN); + eh = (struct ether_header *)PKTDATA(osh, p); + bzero(eh->ether_dhost, ETHER_ADDR_LEN); + bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); + eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); + lsh->type = HTON16(BTA_PROT_L2CAP); + + return dhd_sendpkt(pub, 0, p); +} + +/* txcomplete callback */ +void +dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) +{ + uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); + amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); + uint16 handle = ltoh16(ACL_data->handle); + uint16 llh = HCI_ACL_DATA_HANDLE(handle); + + wl_event_msg_t event; + uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; + amp_hci_event_t *evt; + num_completed_data_blocks_evt_parms_t *parms; + + uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); + + /* update the event struct */ + memset(&event, 0, sizeof(event)); + event.version = hton16(BCM_EVENT_MSG_VERSION); + event.event_type = hton32(WLC_E_BTA_HCI_EVENT); + event.status = 0; + event.reason = 0; + event.auth_type = 0; + event.datalen = hton32(len); + event.flags = 0; + + /* generate Number of Completed Blocks event */ + evt = (amp_hci_event_t *)data; + evt->ecode = HCI_Number_of_Completed_Data_Blocks; + evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); + + parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; + htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); + parms->num_handles = 1; + htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); + parms->completed[0].pkts = 1; + parms->completed[0].blocks = 1; + + dhd_sendup_event_common(dhdp, &event, data); +} + +/* event callback */ +void +dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) +{ + amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; + + switch (evt->ecode) { + case HCI_Command_Complete: { + cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; + switch (ltoh16_ua((uint8 *)&parms->opcode)) { + case HCI_Read_Data_Block_Size: { + read_data_block_size_evt_parms_t *parms2 = + (read_data_block_size_evt_parms_t *)parms->parms; + dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); + break; + } + } + break; + } + + case HCI_Flush_Occurred: { + flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; + dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); + break; + } + default: + break; + } +} diff --git a/src/dhd/sys/dhd_bta.h b/src/dhd/sys/dhd_bta.h new file mode 100644 index 0000000..07d9ceb --- /dev/null +++ b/src/dhd/sys/dhd_bta.h @@ -0,0 +1,39 @@ +/* + * BT-AMP support routines + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: dhd_bta.h,v 1.2 2009-02-26 22:35:56 Exp $ + */ +#ifndef __dhd_bta_h__ +#define __dhd_bta_h__ + +struct dhd_pub; + +extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); + +extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); + +extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); +extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); + + +#endif /* __dhd_bta_h__ */ diff --git a/src/dhd/sys/dhd_bus.h b/src/dhd/sys/dhd_bus.h index 75963c5..bae0713 100644 --- a/src/dhd/sys/dhd_bus.h +++ b/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-2011, 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_bus.h,v 1.4.6.3.2.3.20.5 2009/04/29 04:40:15 Exp $ + * $Id: dhd_bus.h,v 1.14.28.1 2010-12-23 01:13:17 Exp $ */ #ifndef _dhd_bus_h_ @@ -60,6 +60,11 @@ extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); /* Watchdog timer function */ extern bool dhd_bus_watchdog(dhd_pub_t *dhd); +#if defined(DHD_DEBUG) +/* Device console input function */ +extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); +#endif /* defined(DHD_DEBUG) */ + /* Deferred processing for the bus, return TRUE requests reschedule */ extern bool dhd_bus_dpc(struct dhd_bus *bus); extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); diff --git a/src/dhd/sys/dhd_cdc.c b/src/dhd/sys/dhd_cdc.c index a7630f6..b4270e0 100644 --- a/src/dhd/sys/dhd_cdc.c +++ b/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-2011, 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,11 +21,11 @@ * 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.8.2.29 2009/10/05 05:54:04 Exp $ + * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 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 - * for dongle offload). + * for dongle offload.) */ #include <typedefs.h> @@ -41,11 +41,11 @@ #include <dhd_bus.h> #include <dhd_dbg.h> -#ifdef EXT_STA -#include <siutils.h> -#include <wlc_cfg.h> -#include <wlc_pub.h> -#endif /* EXT_STA */ + +#ifdef PROP_TXSTATUS +#include <wlfc_proto.h> +#include <dhd_wlfc.h> +#endif /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN @@ -56,7 +56,7 @@ #endif #define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be atleast SDPCM_RESERVE +#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE * defined in dhd_sdio.c (amount of header tha might be added) * plus any space that might be needed for alignment padding. */ @@ -76,11 +76,14 @@ typedef struct dhd_prot { static int dhdcdc_msg(dhd_pub_t *dhd) { + int err = 0; dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK(dhd); + /* NOTE : cdc->msg.len holds the desired length of the buffer to be * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area * is actually sent to the dongle @@ -89,19 +92,23 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ - return dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); + + DHD_OS_WAKE_UNLOCK(dhd); + return err; } static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) { int ret; + int cdc_len = len+sizeof(cdc_ioctl_t); dhd_prot_t *prot = dhd->prot; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); do { - ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, len+sizeof(cdc_ioctl_t)); + ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); @@ -109,8 +116,8 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) return ret; } -int -dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) +static int +dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) { dhd_prot_t *prot = dhd->prot; cdc_ioctl_t *msg = &prot->msg; @@ -123,7 +130,7 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == WLC_GET_VAR) + if (cmd == WLC_GET_VAR && buf) { if (!strcmp((char *)buf, "bcmerrorstr")) { @@ -141,9 +148,12 @@ 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); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); + msg->flags = htol32(msg->flags); if (buf) memcpy(prot->buf, buf, len); @@ -194,7 +204,7 @@ done: } static int -dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) +dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) { dhd_prot_t *prot = dhd->prot; cdc_ioctl_t *msg = &prot->msg; @@ -208,15 +218,20 @@ 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); CDC_SET_IF_IDX(msg, ifidx); + /* add additional action bits */ + action &= WL_IOCTL_ACTION_MASK; + msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; + msg->flags = htol32(msg->flags); if (buf) memcpy(prot->buf, buf, len); - if ((ret = dhdcdc_msg(dhd)) < 0) + if ((ret = dhdcdc_msg(dhd)) < 0) { + DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); goto done; + } if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) goto done; @@ -243,18 +258,18 @@ done: return ret; } -extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void* arg2); + int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) { dhd_prot_t *prot = dhd->prot; int ret = -1; + uint8 action; if (dhd->busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return ret; + goto done; } - dhd_os_proto_block(dhd); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -264,7 +279,7 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) goto done; if (prot->pending == TRUE) { - DHD_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", + DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, (unsigned long)prot->lastcmd)); if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { @@ -275,10 +290,11 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) prot->pending = TRUE; prot->lastcmd = ioc->cmd; - if (ioc->set) - ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len); + action = ioc->set; + if (action & WL_IOCTL_ACTION_SET) + ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); else { - ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len); + ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); if (ret > 0) ioc->used = ret - sizeof(cdc_ioctl_t); } @@ -288,7 +304,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 */ } @@ -305,8 +320,6 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) prot->pending = FALSE; done: - dhd_os_proto_unblock(dhd); - return ret; } @@ -317,29 +330,1759 @@ dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, return BCME_UNSUPPORTED; } +#ifdef PROP_TXSTATUS void -dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { - bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); + int i; + uint8* ea; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhdp->wlfc_state; + wlfc_hanger_t* h; + wlfc_mac_descriptor_t* mac_table; + wlfc_mac_descriptor_t* interfaces; + char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; + + if (wlfc == NULL) { + bcm_bprintf(strbuf, "wlfc not initialized yet\n"); + return; + } + h = (wlfc_hanger_t*)wlfc->hanger; + if (h == NULL) { + bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); + } + + mac_table = wlfc->destination_entries.nodes; + interfaces = wlfc->destination_entries.interfaces; + bcm_bprintf(strbuf, "---- wlfc stats ----\n"); + if (h) { + bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," + "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", + h->pushed, + h->popped, + h->failed_to_push, + h->failed_to_pop, + h->failed_slotfind, + (h->pushed - h->popped)); + } + + bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " + "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", + wlfc->stats.tlv_parse_failed, + wlfc->stats.credit_request_failed, + wlfc->stats.mac_update_failed, + wlfc->stats.psmode_update_failed, + wlfc->stats.delayq_full_error, + wlfc->stats.sendq_full_error, + wlfc->stats.rollback_failed); + + bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " + "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", + wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], + wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], + wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], + wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], + wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); + +#ifdef PROP_TXSTATUS_DEBUG + bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", + wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], + wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], + wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); +#endif + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (interfaces[i].occupied) { + char* iftype_desc; + + if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) + iftype_desc = "<Unknown"; + else + iftype_desc = iftypes[interfaces[i].iftype]; + + ea = interfaces[i].ea; + bcm_bprintf(strbuf, "INTERFACE[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s\n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + interfaces[i].interface_id, + iftype_desc); + + bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" + "= (%d,%s,%d)\n", + i, + interfaces[i].psq.len, + ((interfaces[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + interfaces[i].requested_credit); + + bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" + "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " + "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", + i, + interfaces[i].psq.q[0].len, + interfaces[i].psq.q[1].len, + interfaces[i].psq.q[2].len, + interfaces[i].psq.q[3].len, + interfaces[i].psq.q[4].len, + interfaces[i].psq.q[5].len, + interfaces[i].psq.q[6].len, + interfaces[i].psq.q[7].len); + } + } + + bcm_bprintf(strbuf, "\n"); + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (mac_table[i].occupied) { + ea = mac_table[i].ea; + bcm_bprintf(strbuf, "MAC_table[%d].ea = " + "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d\n", i, + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], + mac_table[i].interface_id); + + bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" + "= (%d,%s,%d)\n", + i, + mac_table[i].psq.len, + ((mac_table[i].state == + WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), + mac_table[i].requested_credit); +#ifdef PROP_TXSTATUS_DEBUG + bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", + i, mac_table[i].opened_ct, mac_table[i].closed_ct); +#endif + bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" + "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " + "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", + i, + mac_table[i].psq.q[0].len, + mac_table[i].psq.q[1].len, + mac_table[i].psq.q[2].len, + mac_table[i].psq.q[3].len, + mac_table[i].psq.q[4].len, + mac_table[i].psq.q[5].len, + mac_table[i].psq.q[6].len, + mac_table[i].psq.q[7].len); + } + } + +#ifdef PROP_TXSTATUS_DEBUG + { + int avg; + int moving_avg = 0; + int moving_samples; + + if (wlfc->stats.latency_sample_count) { + moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); + + for (i = 0; i < moving_samples; i++) + moving_avg += wlfc->stats.deltas[i]; + moving_avg /= moving_samples; + + avg = (100 * wlfc->stats.total_status_latency) / + wlfc->stats.latency_sample_count; + bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " + "(%d.%d, %03d, %03d)\n", + moving_samples, avg/100, (avg - (avg/100)*100), + wlfc->stats.latency_most_recent, + moving_avg); + } + } + + bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " + "back = (%d,%d,%d,%d,%d,%d)\n", + wlfc->stats.fifo_credits_sent[0], + wlfc->stats.fifo_credits_sent[1], + wlfc->stats.fifo_credits_sent[2], + wlfc->stats.fifo_credits_sent[3], + wlfc->stats.fifo_credits_sent[4], + wlfc->stats.fifo_credits_sent[5], + + wlfc->stats.fifo_credits_back[0], + wlfc->stats.fifo_credits_back[1], + wlfc->stats.fifo_credits_back[2], + wlfc->stats.fifo_credits_back[3], + wlfc->stats.fifo_credits_back[4], + wlfc->stats.fifo_credits_back[5]); + { + uint32 fifo_cr_sent = 0; + uint32 fifo_cr_acked = 0; + uint32 request_cr_sent = 0; + uint32 request_cr_ack = 0; + uint32 bc_mc_cr_ack = 0; + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { + fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; + } + + for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { + fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_sent += + wlfc->destination_entries.nodes[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_sent += + wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; + } + } + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (wlfc->destination_entries.nodes[i].occupied) { + request_cr_ack += + wlfc->destination_entries.nodes[i].dstncredit_acks; + } + } + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + if (wlfc->destination_entries.interfaces[i].occupied) { + request_cr_ack += + wlfc->destination_entries.interfaces[i].dstncredit_acks; + } + } + bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," + "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", + fifo_cr_sent, fifo_cr_acked, + request_cr_sent, request_cr_ack, + wlfc->destination_entries.other.dstncredit_acks, + bc_mc_cr_ack, + wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); + } +#endif /* PROP_TXSTATUS_DEBUG */ + bcm_bprintf(strbuf, "\n"); + bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" + "(freed,free_err,rollback)) = " + "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", + wlfc->stats.pktin, + wlfc->stats.pkt2bus, + wlfc->stats.txstatus_in, + wlfc->stats.dhd_hdrpulls, + + wlfc->stats.pktdropped, + wlfc->stats.wlfc_header_only_pkt, + wlfc->stats.wlc_tossed_pkts, + + wlfc->stats.pkt_freed, + wlfc->stats.pkt_free_err, wlfc->stats.rollback); + + bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " + "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", + + wlfc->stats.d11_suppress, + wlfc->stats.wl_suppress, + wlfc->stats.bad_suppress, + + wlfc->stats.psq_d11sup_enq, + wlfc->stats.psq_wlsup_enq, + wlfc->stats.psq_hostq_enq, + wlfc->stats.mac_handle_notfound, + + wlfc->stats.psq_d11sup_retx, + wlfc->stats.psq_wlsup_retx, + wlfc->stats.psq_hostq_retx); + return; +} + +/* Create a place to store all packet pointers submitted to the firmware until + a status comes back, suppress or otherwise. + + hang-er: noun, a contrivance on which things are hung, as a hook. +*/ +static void* +dhd_wlfc_hanger_create(osl_t *osh, int max_items) +{ + int i; + wlfc_hanger_t* hanger; + + /* allow only up to a specific size for now */ + ASSERT(max_items == WLFC_HANGER_MAXITEMS); + + if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) + return NULL; + + memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); + hanger->max_items = max_items; + + for (i = 0; i < hanger->max_items; i++) { + hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } + return hanger; } -#ifdef APSTA_PINGTEST -extern struct ether_addr guest_eas[MAX_GUEST]; +static int +dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) +{ + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); + return BCME_OK; + } + return BCME_BADARG; +} + +static uint16 +dhd_wlfc_hanger_get_free_slot(void* hanger) +{ + int i; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h) { + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) + return (uint16)i; + } + } + h->failed_slotfind++; + return WLFC_HANGER_MAXITEMS; +} + +static int +dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; + h->items[slot_id].pkt = pkt; + h->items[slot_id].identifier = slot_id; + h->pushed++; + } + else { + h->failed_to_push++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) +{ + int rc = BCME_OK; + wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; + + /* this packet was not pushed at the time it went to the firmware */ + if (slot_id == WLFC_HANGER_MAXITEMS) + return BCME_NOTFOUND; + + if (h) { + if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { + *pktout = h->items[slot_id].pkt; + if (remove_from_hanger) { + h->items[slot_id].state = + WLFC_HANGER_ITEM_STATE_FREE; + h->items[slot_id].pkt = NULL; + h->items[slot_id].identifier = 0; + h->popped++; + } + } + else { + h->failed_to_pop++; + rc = BCME_NOTFOUND; + } + } + else + rc = BCME_BADARG; + return rc; +} + +static int +_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, + uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) +{ + uint32 wl_pktinfo = 0; + uint8* wlh; + uint8 dataOffset; + uint8 fillers; + uint8 tim_signal_len = 0; + + struct bdc_header *h; + + if (tim_signal) { + tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + } + + /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ + dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; + fillers = ROUNDUP(dataOffset, 4) - dataOffset; + dataOffset += fillers; + + PKTPUSH(ctx->osh, p, dataOffset); + wlh = (uint8*) PKTDATA(ctx->osh, p); + + wl_pktinfo = htol32(htodtag); + + wlh[0] = WLFC_CTL_TYPE_PKTTAG; + wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; + memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); + + if (tim_signal_len) { + wlh[dataOffset - fillers - tim_signal_len ] = + WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 1] = + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; + wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; + wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; + } + if (fillers) + memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); + + PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); + h = (struct bdc_header *)PKTDATA(ctx->osh, p); + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (PKTSUMNEEDED(p)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + + h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->dataOffset = dataOffset >> 2; + BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) +{ + struct bdc_header *h; + + if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { + WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); + return BCME_ERROR; + } + h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); + + /* pull BDC header */ + PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); + /* pull wl-header */ + PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); + return BCME_OK; +} + +static wlfc_mac_descriptor_t* +_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) +{ + int i; + wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; + uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); + uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); + + /* no lookup necessary, only if this packet belongs to STA interface */ + if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || + ETHER_ISMULTI(dstn) || + (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && + (ctx->destination_entries.interfaces[ifid].occupied)) { + return &ctx->destination_entries.interfaces[ifid]; + } + + for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { + if (table[i].occupied) { + if (table[i].interface_id == ifid) { + if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) + return &table[i]; + } + } + } + return &ctx->destination_entries.other; +} + +static int +_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, + void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) +{ + /* + put the packet back to the head of queue + + - a packet from send-q will need to go back to send-q and not delay-q + since that will change the order of packets. + - suppressed packet goes back to suppress sub-queue + - pull out the header, if new or delayed packet + + Note: hslot is used only when header removal is done. + */ + wlfc_mac_descriptor_t* entry; + void* pktout; + int rc = BCME_OK; + int prec; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + prec = DHD_PKTTAG_FIFO(PKTTAG(p)); + if (entry != NULL) { + if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { + /* wl-header is saved for suppressed packets */ + if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + } + else { + /* remove header first */ + _dhd_wlfc_pullheader(ctx, p); + + if (pkt_type == eWLFC_PKTTYPE_DELAYED) { + /* delay-q packets are going to delay-q */ + if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + } + else { + /* these are going to SENDQ */ + if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + } + /* free the hanger slot */ + dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); + + /* decrement sequence count */ + WLFC_DECR_SEQCOUNT(entry, prec); + } + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the firmware (for pspoll etc.) + */ + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + entry->requested_credit++; + } + } + else { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + rc = BCME_ERROR; + } + if (rc != BCME_OK) + ctx->stats.rollback_failed++; + else + ctx->stats.rollback++; + + return rc; +} + +static void +_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) +{ + if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { + /* start traffic */ + ctx->hostif_flow_state[if_id] = OFF; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("F")); + /* dhd_txflowcontrol(ctx->dhdp, if_id, OFF); */ + ctx->toggle_host_if = 0; + } + if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { + /* stop traffic */ + ctx->hostif_flow_state[if_id] = ON; + /* + WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", + pq->len, if_id, __FUNCTION__)); + */ + WLFC_DBGMESG(("N")); + /* dhd_txflowcontrol(ctx->dhdp, if_id, ON); */ + ctx->host_ifidx = if_id; + ctx->toggle_host_if = 1; + } + return; +} + +static int +_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + uint8 ta_bmp) +{ + int rc = BCME_OK; + void* p = NULL; + int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; + + /* allocate a dummy packet */ + p = PKTGET(ctx->osh, dummylen, TRUE); + if (p) { + PKTPULL(ctx->osh, p, dummylen); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); + _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); + DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); +#ifdef PROP_TXSTATUS_DEBUG + ctx->stats.signal_only_pkts_sent++; #endif + dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); + } + else { + DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", + __FUNCTION__, dummylen)); + rc = BCME_NOMEM; + } + return rc; +} + +/* Return TRUE if traffic availability changed */ +static bool +_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + int prec) +{ + bool rc = FALSE; + + if (entry->state == WLFC_STATE_CLOSE) { + if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && + (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { + + if (entry->traffic_pending_bmp & NBITVAL(prec)) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp & ~ NBITVAL(prec); + } + } + else { + if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { + rc = TRUE; + entry->traffic_pending_bmp = + entry->traffic_pending_bmp | NBITVAL(prec); + } + } + } + if (rc) { + /* request a TIM update to firmware at the next piggyback opportunity */ + if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { + entry->send_tim_signal = 1; + _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + entry->send_tim_signal = 0; + } + else { + rc = FALSE; + } + } + return rc; +} + +static int +_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) +{ + wlfc_mac_descriptor_t* entry; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_NOTFOUND; + } + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { + ctx->stats.delayq_full_error++; + /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ + WLFC_DBGMESG(("s")); + return BCME_ERROR; + } + /* A packet has been pushed, update traffic availability bitmap, if applicable */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); + return BCME_OK; +} + +static int +_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) +{ + int rc = BCME_OK; + int hslot = WLFC_HANGER_MAXITEMS; + bool send_tim_update = FALSE; + uint32 htod = 0; + uint8 free_ctr; + + *slot = hslot; + + if (entry == NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, p); + } + + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_ERROR; + } + if (entry->send_tim_signal) { + send_tim_update = TRUE; + entry->send_tim_signal = 0; + entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; + } + if (header_needed) { + hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); + free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + } + else { + hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + } + WLFC_PKTID_HSLOT_SET(htod, hslot); + WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); + DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); + WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); + WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); + WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); + + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { + /* + Indicate that this packet is being sent in response to an + explicit request from the firmware side. + */ + WLFC_PKTFLAG_SET_PKTREQUESTED(htod); + } + else { + WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); + } + if (header_needed) { + rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod); + if (rc == BCME_OK) { + DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); + /* + a new header was created for this packet. + push to hanger slot and scrub q. Since bus + send succeeded, increment seq number as well. + */ + rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); + if (rc == BCME_OK) { + /* increment free running sequence count */ + WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); +#ifdef PROP_TXSTATUS_DEBUG + ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = + OSL_SYSUPTIME(); +#endif + } + else { + WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n", + __FUNCTION__, rc)); + } + } + } + else { + /* remove old header */ + _dhd_wlfc_pullheader(ctx, p); + + hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); + /* push new header */ + _dhd_wlfc_pushheader(ctx, p, send_tim_update, + entry->traffic_lastreported_bmp, entry->mac_handle, htod); + } + *slot = hslot; + return rc; +} + +static int +_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, + wlfc_mac_descriptor_t* entry, int prec) +{ + if (ctx->destination_entries.interfaces[entry->interface_id].iftype == + WLC_E_IF_ROLE_P2P_GO) { + /* - destination interface is of type p2p GO. + For a p2pGO interface, if the destination is OPEN but the interface is + CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is + destination-specific-credit left send packets. This is because the + firmware storing the destination-specific-requested packet in queue. + */ + if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) + return 1; + } + /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ + if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && + (entry->requested_packet == 0)) || + (!(entry->ac_bitmap & (1 << prec)))) + return 1; + + return 0; +} + +static void* +_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, + int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) +{ + wlfc_mac_descriptor_t* entry; + wlfc_mac_descriptor_t* table; + uint8 token_pos; + int total_entries; + void* p = NULL; + int pout; + int i; + + *entry_out = NULL; + token_pos = ctx->token_pos[prec]; + /* most cases a packet will count against FIFO credit */ + *ac_credit_spent = 1; + *needs_hdr = 1; + + /* search all entries, include nodes as well as interfaces */ + table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; + total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); + + for (i = 0; i < total_entries; i++) { + entry = &table[(token_pos + i) % total_entries]; + if (entry->occupied) { + if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { + p = pktq_mdeq(&entry->psq, + /* higher precedence will be picked up first, + i.e. suppressed packets before delayed ones + */ + (NBITVAL((prec << 1) + 1) | NBITVAL((prec << 1))), + &pout); + if (p != NULL) { + /* did the packet come from suppress sub-queue? */ + if (pout == ((prec << 1) + 1)) { + /* + this packet was suppressed and was sent on the bus + previously; this already has a header + */ + *needs_hdr = 0; + } + if (entry->requested_credit > 0) { + entry->requested_credit--; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_sent_packets++; +#endif + /* + if the packet was pulled out while destination is in + closed state but had a non-zero packets requested, + then this should not count against the FIFO credit. + That is due to the fact that the firmware will + most likely hold onto this packet until a suitable + time later to push it to the appropriate AC FIFO. + */ + if (entry->state == WLFC_STATE_CLOSE) + *ac_credit_spent = 0; + } + else if (entry->requested_packet > 0) { + entry->requested_packet--; + DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); + if (entry->state == WLFC_STATE_CLOSE) + *ac_credit_spent = 0; + } + /* move token to ensure fair round-robin */ + ctx->token_pos[prec] = + (token_pos + i + 1) % total_entries; + *entry_out = entry; + _dhd_wlfc_flow_control_check(ctx, &entry->psq, + DHD_PKTTAG_IF(PKTTAG(p))); + /* + A packet has been picked up, update traffic + availability bitmap, if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + return p; + } + } + } + } + return NULL; +} + +static void* +_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec, uint8* ac_credit_spent) +{ + wlfc_mac_descriptor_t* entry; + void* p; + + /* most cases a packet will count against FIFO credit */ + *ac_credit_spent = 1; + + p = pktq_pdeq(&ctx->SENDQ, prec); + if (p != NULL) { + if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) + /* bc/mc packets do not have a delay queue */ + return p; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + + if (entry == NULL) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return p; + } + + while ((p != NULL) && _dhd_wlfc_is_destination_closed(ctx, entry, prec)) { + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { + WLFC_DBGMESG(("D")); + /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ + PKTFREE(ctx->osh, p, TRUE); + ctx->stats.delayq_full_error++; + } + /* + A packet has been pushed, update traffic availability bitmap, + if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); + p = pktq_pdeq(&ctx->SENDQ, prec); + if (p == NULL) + break; + + entry = _dhd_wlfc_find_table_entry(ctx, p); + + if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { + return p; + } + } + if (p) { + if (entry->requested_packet == 0) { + if (entry->requested_credit > 0) + entry->requested_credit--; + } + else { + entry->requested_packet--; + DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); + } + if (entry->state == WLFC_STATE_CLOSE) + *ac_credit_spent = 0; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_sent_packets++; +#endif + } + if (p) + _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); + } + return p; +} + +static int +_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) +{ + int rc = BCME_OK; + + if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { + entry->occupied = 1; + entry->state = WLFC_STATE_OPEN; + entry->requested_credit = 0; + entry->interface_id = ifid; + entry->iftype = iftype; + entry->ac_bitmap = 0xff; /* update this when handling APSD */ + /* for an interface entry we may not care about the MAC address */ + if (ea != NULL) + memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); + pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); + } + else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { + entry->occupied = 0; + entry->state = WLFC_STATE_CLOSE; + entry->requested_credit = 0; + /* enable after packets are queued-deqeued properly. + pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); + */ + } + return rc; +} + +int +dhd_wlfc_interface_entry_update(void* state, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + wlfc_mac_descriptor_t* entry; + + if (ifid >= WLFC_MAX_IFNUM) + return BCME_BADARG; + + entry = &ctx->destination_entries.interfaces[ifid]; + return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); +} + +int +dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + + /* update the AC FIFO credit map */ + ctx->FIFO_credit[0] = credits[0]; + ctx->FIFO_credit[1] = credits[1]; + ctx->FIFO_credit[2] = credits[2]; + ctx->FIFO_credit[3] = credits[3]; + /* credit for bc/mc packets */ + ctx->FIFO_credit[4] = credits[4]; + /* credit for ATIM FIFO is not used yet. */ + return BCME_OK; +} + +int +dhd_wlfc_enque_sendq(void* state, int prec, void* p) +{ + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + + if ((state == NULL) || + /* prec = AC_COUNT is used for bc/mc queue */ + (prec > AC_COUNT) || + (p == NULL)) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { + ctx->stats.sendq_full_error++; + /* + WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n", + __FUNCTION__, __LINE__, ctx->SENDQ.len)); + */ + WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); + WLFC_DBGMESG(("Q")); + PKTFREE(ctx->osh, p, TRUE); + return BCME_ERROR; + } + ctx->stats.pktin++; + /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ + return BCME_OK; +} + +int +dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) +{ + int ac; + int credit; + uint8 ac_fifo_credit_spent; + uint8 needs_hdr; + uint32 hslot; + void* p; + int rc; + athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; + wlfc_mac_descriptor_t* mac_entry; + + if ((state == NULL) || + (fcommit == NULL)) { + WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); + return BCME_BADARG; + } + + /* + Commit packets for regular AC traffic. Higher priority first. + + -NOTE: + If the bus between the host and firmware is overwhelmed by the + traffic from host, it is possible that higher priority traffic + starves the lower priority queue. If that occurs often, we may + have to employ weighted round-robin or ucode scheme to avoid + low priority packet starvation. + */ + for (ac = AC_COUNT; ac >= 0; ac--) { + for (credit = 0; credit < ctx->FIFO_credit[ac];) { + p = _dhd_wlfc_deque_delayedq(ctx, ac, &ac_fifo_credit_spent, &needs_hdr, + &mac_entry); + if (p == NULL) + break; + /* + if ac_fifo_credit_spent = 0 + + This packet will not count against the FIFO credit. + To ensure the txstatus corresponding to this packet + does not provide an implied credit (default behavior) + mark the packet accordingly. + + if ac_fifo_credit_spent = 1 + + This is a normal packet and it counts against the FIFO + credit count. + */ + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent); + rc = _dhd_wlfc_pretx_pktprocess(ctx, mac_entry, p, needs_hdr, &hslot); + + if (rc == BCME_OK) + rc = fcommit(commit_ctx, p); + else + ctx->stats.generic_error++; + + if (rc == BCME_OK) { + ctx->stats.pkt2bus++; + if (ac_fifo_credit_spent) { + ctx->stats.sendq_pkts[ac]++; + WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); + /* + 1 FIFO credit has been spent by sending this packet + to the device. + */ + credit++; + } + } + else { + /* bus commit has failed, rollback. */ + rc = _dhd_wlfc_rollback_packet_toq(ctx, + p, + /* + - remove wl-header for a delayed packet + - save wl-header header for suppressed packets + */ + (needs_hdr ? eWLFC_PKTTYPE_DELAYED : + eWLFC_PKTTYPE_SUPPRESSED), + hslot); + if (rc != BCME_OK) + ctx->stats.rollback_failed++; + } + } + ctx->FIFO_credit[ac] -= credit; + /* packets from SENDQ are fresh and they'd need header */ + needs_hdr = 1; + for (credit = 0; credit < ctx->FIFO_credit[ac];) { + p = _dhd_wlfc_deque_sendq(ctx, ac, &ac_fifo_credit_spent); + if (p == NULL) + break; + + DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent); + rc = _dhd_wlfc_pretx_pktprocess(ctx, NULL, p, needs_hdr, &hslot); + if (rc == BCME_OK) + rc = fcommit(commit_ctx, p); + else + ctx->stats.generic_error++; + + if (rc == BCME_OK) { + ctx->stats.pkt2bus++; + if (ac_fifo_credit_spent) { + WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); + ctx->stats.sendq_pkts[ac]++; + credit++; + } + } + else { + /* bus commit has failed, rollback. */ + rc = _dhd_wlfc_rollback_packet_toq(ctx, + p, + /* remove wl-header while rolling back */ + eWLFC_PKTTYPE_NEW, + hslot); + if (rc != BCME_OK) + ctx->stats.rollback_failed++; + } + } + ctx->FIFO_credit[ac] -= credit; + } + return BCME_OK; +} + +static uint8 +dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) +{ + wlfc_mac_descriptor_t* table = + ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; + uint8 table_index; + + if (ea != NULL) { + for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { + if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && + table[table_index].occupied) + return table_index; + } + } + return WLFC_MAC_DESC_ID_INVALID; +} + +void +dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + void* p; + + if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.signal_only_pkts_freed++; +#endif + /* is this a signal-only packet? */ + PKTFREE(wlfc->osh, txp, TRUE); + return; + } + if (!success) { + WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", + __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG + (PKTTAG(txp))), &p, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, txp, FALSE); + PKTFREE(wlfc->osh, txp, TRUE); + + /* return the credit, if necessary */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) + wlfc->FIFO_credit[DHD_PKTTAG_FIFO(PKTTAG(txp))]++; + } + return; +} + +/* Handle discard or suppress indication */ +static int +dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) +{ + uint8 status_flag; + uint32 status; + int ret; + int remove_from_hanger = 1; + void* pktbuf; + uint8 fifo_id; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + wlfc->stats.txstatus_in++; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed++; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts++; + } + + ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); + if (ret != BCME_OK) { + /* do something */ + return ret; + } + + if (!remove_from_hanger) { + /* this packet was suppressed */ + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + entry->generation = WLFC_PKTID_GEN(status); + } + +#ifdef PROP_TXSTATUS_DEBUG + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ + WLFC_PKTID_HSLOT_GET(status)].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { + wlfc->FIFO_credit[fifo_id]++; + } + } + else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!entry) { + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + } + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), + &pktbuf, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, pktbuf, FALSE); + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + } + else { + dhd_txcomplete(dhd, pktbuf, TRUE); + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + return BCME_OK; +} + +static int +dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) +{ + int i; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { +#ifdef PROP_TXSTATUS_DEBUG + wlfc->stats.fifo_credits_back[i] += credits[i]; +#endif + /* update FIFO credits */ + if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) + wlfc->FIFO_credit[i] += credits[i]; + } + return BCME_OK; +} + +static int +dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) +{ + (void)dhd; + (void)rssi; + return BCME_OK; +} + +static int +dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + int rc; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 existing_index; + uint8 table_index; + uint8 ifid; + uint8* ea; + + WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", + __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], + ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), + WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); + + table = wlfc->destination_entries.nodes; + table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); + ifid = value[1]; + ea = &value[2]; + + if (type == WLFC_CTL_TYPE_MACDESC_ADD) { + existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); + if (existing_index == WLFC_MAC_DESC_ID_INVALID) { + /* this MAC entry does not exist, create one */ + if (!table[table_index].occupied) { + table[table_index].mac_handle = value[0]; + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_ADD, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea); + } + else { + /* the space should have been empty, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + else { + /* + there is an existing entry, move it to new index + if necessary. + */ + if (existing_index != table_index) { + /* if we already have an entry, free the old one */ + table[existing_index].occupied = 0; + table[existing_index].state = WLFC_STATE_CLOSE; + table[existing_index].requested_credit = 0; + table[existing_index].interface_id = 0; + } + } + } + if (type == WLFC_CTL_TYPE_MACDESC_DEL) { + if (table[table_index].occupied) { + rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], + eWLFC_MAC_ENTRY_ACTION_DEL, ifid, + wlfc->destination_entries.interfaces[ifid].iftype, + ea); + } + else { + /* the space should have been occupied, but it's not */ + wlfc->stats.mac_update_failed++; + } + } + return BCME_OK; +} + +static int +dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle = value[0]; + int i; + + table = wlfc->destination_entries.nodes; + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + /* a fresh PS mode should wipe old ps credits? */ + desc->requested_credit = 0; + if (type == WLFC_CTL_TYPE_MAC_OPEN) { + desc->state = WLFC_STATE_OPEN; + DHD_WLFC_CTRINC_MAC_OPEN(desc); + } + else { + desc->state = WLFC_STATE_CLOSE; + DHD_WLFC_CTRINC_MAC_CLOSE(desc); + /* + Indicate to firmware if there is any traffic pending. + */ + for (i = AC_BE; i < AC_COUNT; i++) { + _dhd_wlfc_traffic_pending_check(wlfc, desc, i); + } + } + } + else { + wlfc->stats.psmode_update_failed++; + } + return BCME_OK; +} + +static int +dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) +{ + /* Handle PS on/off indication */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + uint8 if_id = value[0]; + + if (if_id < WLFC_MAX_IFNUM) { + table = wlfc->destination_entries.interfaces; + if (table[if_id].occupied) { + if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { + table[if_id].state = WLFC_STATE_OPEN; + /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ + } + else { + table[if_id].state = WLFC_STATE_CLOSE; + /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ + } + return BCME_OK; + } + } + wlfc->stats.interface_update_failed++; + + return BCME_OK; +} + +static int +dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 credit; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + credit = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_credit = credit; + + desc->ac_bitmap = value[2]; + } + else { + wlfc->stats.credit_request_failed++; + } + return BCME_OK; +} + +static int +dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) +{ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_mac_descriptor_t* desc; + uint8 mac_handle; + uint8 packet_count; + + table = wlfc->destination_entries.nodes; + mac_handle = value[1]; + packet_count = value[0]; + + desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; + if (desc->occupied) { + desc->requested_packet = packet_count; + + desc->ac_bitmap = value[2]; + } + else { + wlfc->stats.packet_request_failed++; + } + return BCME_OK; +} + +static int +dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len) +{ + uint8 type, len; + uint8* value; + uint8* tmpbuf; + uint16 remainder = tlv_hdr_len; + uint16 processed = 0; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); + if (remainder) { + while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { + type = tmpbuf[processed]; + if (type == WLFC_CTL_TYPE_FILLER) { + remainder -= 1; + processed += 1; + continue; + } + + len = tmpbuf[processed + 1]; + value = &tmpbuf[processed + 2]; + + if (remainder < (2 + len)) + break; + + remainder -= 2 + len; + processed += 2 + len; + if (type == WLFC_CTL_TYPE_TXSTATUS) + dhd_wlfc_txstatus_update(dhd, value); + + else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) + dhd_wlfc_fifocreditback_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_RSSI) + dhd_wlfc_rssi_indicate(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) + dhd_wlfc_credit_request(dhd, value); + + else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) + dhd_wlfc_packet_request(dhd, value); + + else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || + (type == WLFC_CTL_TYPE_MAC_CLOSE)) + dhd_wlfc_psmode_update(dhd, value, type); + + else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || + (type == WLFC_CTL_TYPE_MACDESC_DEL)) + dhd_wlfc_mac_table_update(dhd, value, type); + + else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || + (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { + dhd_wlfc_interface_update(dhd, value, type); + } + } + if (remainder != 0) { + /* trouble..., something is not right */ + wlfc->stats.tlv_parse_failed++; + } + } + return BCME_OK; +} + +int +dhd_wlfc_init(dhd_pub_t *dhd) +{ + char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ + /* enable all signals & indicate host proptxstatus logic is active */ + uint32 tlv = dhd->wlfc_enabled? + WLFC_FLAGS_RSSI_SIGNALS | + WLFC_FLAGS_XONXOFF_SIGNALS | + WLFC_FLAGS_CREDIT_STATUS_SIGNALS | + WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0; + + dhd->wlfc_state = NULL; + + /* + try to enable/disable signaling by sending "tlv" iovar. if that fails, + fallback to no flow control? Print a message for now. + */ + + /* enable proptxtstatus signaling by default */ + bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { + DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); + } + else { + /* + Leaving the message for now, it should be removed after a while; once + the tlv situation is stable. + */ + DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", + dhd->wlfc_enabled?"enabled":"disabled", tlv)); + } + return BCME_OK; +} + +int +dhd_wlfc_enable(dhd_pub_t *dhd) +{ + int i; + athost_wl_status_info_t* wlfc; + + if (!dhd->wlfc_enabled || dhd->wlfc_state) + return BCME_OK; + + /* allocate space to track txstatus propagated from firmware */ + dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); + if (dhd->wlfc_state == NULL) + return BCME_NOMEM; + + /* initialize state space */ + wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; + memset(wlfc, 0, sizeof(athost_wl_status_info_t)); + + /* remember osh & dhdp */ + wlfc->osh = dhd->osh; + wlfc->dhdp = dhd; + + wlfc->hanger = + dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); + if (wlfc->hanger == NULL) { + MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + return BCME_NOMEM; + } + + /* initialize all interfaces to accept traffic */ + for (i = 0; i < WLFC_MAX_IFNUM; i++) { + wlfc->hostif_flow_state[i] = OFF; + } + + /* + create the SENDQ containing + sub-queues for all AC precedences + 1 for bc/mc traffic + */ + pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); + + wlfc->destination_entries.other.state = WLFC_STATE_OPEN; + /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ + wlfc->destination_entries.other.ac_bitmap = 0x1f; + wlfc->destination_entries.other.interface_id = 0; + + wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; + + return BCME_OK; +} + +/* release all packet resources */ +void +dhd_wlfc_cleanup(dhd_pub_t *dhd) +{ + int i; + int total_entries; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + wlfc_mac_descriptor_t* table; + wlfc_hanger_t* h; + + if (dhd->wlfc_state == NULL) + return; + + total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); + /* search all entries, include nodes as well as interfaces */ + table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; + + for (i = 0; i < total_entries; i++) { + if (table[i].occupied) { + if (table[i].psq.len) { + WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", + __FUNCTION__, i, table[i].psq.len)); + /* release packets held in DELAYQ */ + pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); + } + table[i].occupied = 0; + } + } + /* release packets held in SENDQ */ + if (wlfc->SENDQ.len) + pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); + /* any in the hanger? */ + h = (wlfc_hanger_t*)wlfc->hanger; + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); + } + } + return; +} + +void +dhd_wlfc_deinit(dhd_pub_t *dhd) +{ + /* cleanup all psq related resources */ + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + if (dhd->wlfc_state == NULL) + return; + +#ifdef PROP_TXSTATUS_DEBUG + { + int i; + wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; + for (i = 0; i < h->max_items; i++) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { + WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", + __FUNCTION__, i, h->items[i].pkt, + DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); + } + } + } +#endif + /* delete hanger */ + dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); + + /* free top structure */ + MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); + dhd->wlfc_state = NULL; + return; +} +#endif /* PROP_TXSTATUS */ + +void +dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) +{ + bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state) + dhd_wlfc_dump(dhdp, strbuf); +#endif +} void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) { #ifdef BDC struct bdc_header *h; -#ifdef APSTA_PINGTEST - struct ether_header *eh; - int i; -#ifdef DHD_DEBUG - char eabuf1[ETHER_ADDR_STR_LEN]; - char eabuf2[ETHER_ADDR_STR_LEN]; -#endif /* DHD_DEBUG */ -#endif /* APSTA_PINGTEST */ #endif /* BDC */ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -347,10 +2090,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) #ifdef BDC /* Push BDC header used to convey priority for buses that don't */ -#ifdef APSTA_PINGTEST - eh = (struct ether_header *)PKTDATA(dhd->osh, pktbuf); -#endif - PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); @@ -359,34 +2098,16 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) if (PKTSUMNEEDED(pktbuf)) h->flags |= BDC_FLAG_SUM_NEEDED; -#ifdef EXT_STA - /* save pkt encryption exemption info for dongle */ - h->flags &= ~BDC_FLAG_EXEMPT; - h->flags |= (WLPKTFLAG_EXEMPT_GET(WLPKTTAG(pktbuf)) & BDC_FLAG_EXEMPT); -#endif /* EXT_STA */ h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); h->flags2 = 0; -#ifdef APSTA_PINGTEST - for (i = 0; i < MAX_GUEST; ++i) { - if (!ETHER_ISNULLADDR(eh->ether_dhost) && - bcmp(eh->ether_dhost, guest_eas[i].octet, ETHER_ADDR_LEN) == 0) { - DHD_TRACE(("send on if 1; sa %s, da %s\n", - bcm_ether_ntoa((struct ether_addr *)(eh->ether_shost), eabuf1), - bcm_ether_ntoa((struct ether_addr *)(eh->ether_dhost), eabuf2))); - /* assume all guest STAs are on interface 1 */ - h->flags2 = 1; - break; - } - } -#endif /* APSTA_PINGTEST */ - h->rssi = 0; + h->dataOffset = 0; #endif /* BDC */ BDC_SET_IF_IDX(h, ifidx); } int -dhd_prot_hdrpull(dhd_pub_t *dhd, uint *ifidx, void *pktbuf) +dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf) { #ifdef BDC struct bdc_header *h; @@ -405,15 +2126,19 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, uint *ifidx, void *pktbuf) h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); - if (ifidx) { - *ifidx = (int)BDC_GET_IF_IDX(h); - ASSERT(*ifidx < DHD_MAX_IFS); + if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { + DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", + __FUNCTION__, *ifidx)); + return BCME_ERROR; } if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { - DHD_ERROR(("%s: non-BDC packet received, flags 0x%x\n", + DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", dhd_ifname(dhd, *ifidx), h->flags)); - return BCME_ERROR; + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) + h->dataOffset = 0; + else + return BCME_ERROR; } if (h->flags & BDC_FLAG_SUM_GOOD) { @@ -423,10 +2148,32 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, uint *ifidx, void *pktbuf) } PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); #endif /* BDC */ + if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) { + DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, + PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4))); + return BCME_ERROR; + } + +#ifdef PROP_TXSTATUS + if (dhd->wlfc_state && + ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode + != WLFC_FCMODE_NONE && + (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) { + /* + - parse txstatus only for packets that came from the firmware + */ + dhd_os_wlfc_block(dhd); + dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2)); + ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; + dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, + dhd->bus); + dhd_os_wlfc_unblock(dhd); + } +#endif /* PROP_TXSTATUS */ + PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2)); return 0; } @@ -435,10 +2182,17 @@ dhd_prot_attach(dhd_pub_t *dhd) { dhd_prot_t *cdc; +#ifndef DHD_USE_STATIC_BUF if (!(cdc = (dhd_prot_t *)MALLOC(dhd->osh, sizeof(dhd_prot_t)))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; } +#else + if (!(cdc = (dhd_prot_t *)dhd_os_prealloc(DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } +#endif /* DHD_USE_STATIC_BUF */ memset(cdc, 0, sizeof(dhd_prot_t)); /* ensure that the msg buf directly follows the cdc msg struct */ @@ -455,8 +2209,10 @@ dhd_prot_attach(dhd_pub_t *dhd) return 0; fail: +#ifndef DHD_USE_STATIC_BUF if (cdc != NULL) MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); +#endif return BCME_NOMEM; } @@ -464,7 +2220,12 @@ fail: void dhd_prot_detach(dhd_pub_t *dhd) { +#ifdef PROP_TXSTATUS + dhd_wlfc_deinit(dhd); +#endif +#ifndef DHD_USE_STATIC_BUF MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); +#endif dhd->prot = NULL; } @@ -481,85 +2242,47 @@ dhd_prot_dstats(dhd_pub_t *dhd) return; } -int -dhd_preinit_ioctls(dhd_pub_t *dhd) -{ - char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WLC_IOCTL_SMLEN]; /* Room for "event_msgs" + '\0' + bitvec */ - uint up = 0; - uint roamvar = 1; - uint power_mode = PM_FAST; - uint32 dongle_align = DHD_SDALIGN; - uint32 glom = 0; - int ret; - uint bcn_timeout = 3; - - /* Get the device MAC address */ - strcpy(iovbuf, "cur_etheraddr"); - 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)); - return BCME_NOTUP; - } - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); - - /* Set Country code */ - if (dhd->country_code[0] != 0) { - if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY, - dhd->country_code, sizeof(dhd->country_code)) < 0) { - DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); - } - } - - /* Set PowerSave mode */ - dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); - - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); - /* Setup timeout if Beacons are lost to report link down */ - if (roamvar) { - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); - } - - /* Disable build-in roaming to allowed ext supplicant to take of romaing */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); - - /* Force STA UP */ - dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up)); - - - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); - bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - - /* Setup event_msgs */ - setbit(eventmask, WLC_E_SET_SSID); - setbit(eventmask, WLC_E_PRUNE); - setbit(eventmask, WLC_E_AUTH); - setbit(eventmask, WLC_E_REASSOC); - setbit(eventmask, WLC_E_REASSOC_IND); - setbit(eventmask, WLC_E_DEAUTH_IND); - setbit(eventmask, WLC_E_DISASSOC_IND); - setbit(eventmask, WLC_E_DISASSOC); - setbit(eventmask, WLC_E_JOIN); - setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); - setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_NDIS_LINK); - setbit(eventmask, WLC_E_MIC_ERROR); - setbit(eventmask, WLC_E_PMKID_CACHE); - setbit(eventmask, WLC_E_TXFAIL); - setbit(eventmask, WLC_E_JOIN_START); - setbit(eventmask, WLC_E_SCAN_COMPLETE); - - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +int dhd_set_suspend(int value, dhd_pub_t *dhd) +{ + int power_mode = PM_MAX; + wl_pkt_filter_enable_t enable_parm; + char iovbuf[32]; + int bcn_li_dtim = 3; + +#define htod32(i) i + + if (dhd && dhd->up) { + if (value) { + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, + (char *)&power_mode, sizeof(power_mode), TRUE, 0); + /* Enable packet filter, only allow unicast packet to send up */ + enable_parm.id = htod32(100); + enable_parm.enable = htod32(1); + bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, + sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + /* set bcn_li_dtim */ + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } else { + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); + /* disable pkt filter */ + enable_parm.id = htod32(100); + enable_parm.enable = htod32(0); + bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, + sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + /* set bcn_li_dtim */ + bcn_li_dtim = 0; + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } + } + return 0; } @@ -567,14 +2290,28 @@ int dhd_prot_init(dhd_pub_t *dhd) { int ret = 0; + wlc_rev_info_t revinfo; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + /* Get the device rev info */ + memset(&revinfo, 0, sizeof(revinfo)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); + if (ret < 0) + goto done; + + ret = dhd_preinit_ioctls(dhd); /* Always assumes wl for now */ dhd->iswl = TRUE; +#ifdef PROP_TXSTATUS + ret = dhd_wlfc_init(dhd); +#endif + goto done; + +done: return ret; } diff --git a/src/dhd/sys/dhd_common.c b/src/dhd/sys/dhd_common.c index ee7e4cb..ae92489 100644 --- a/src/dhd/sys/dhd_common.c +++ b/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-2011, 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.8.2.33 2009/09/29 00:09:57 Exp $ + * $Id: dhd_common.c,v 1.57.2.22 2011-02-01 18:38:37 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -31,22 +31,64 @@ #include <bcmendian.h> #include <dngl_stats.h> +#include <wlioctl.h> #include <dhd.h> + +#include <proto/bcmevent.h> + #include <dhd_bus.h> #include <dhd_proto.h> #include <dhd_dbg.h> #include <msgtrace.h> +#include <proto/bt_amp_hci.h> +#include <dhd_bta.h> + +#ifdef PROP_TXSTATUS +#include <wlfc_proto.h> +#include <dhd_wlfc.h> +#endif + +#ifdef WLMEDIA_HTSF +extern void htsf_update(struct dhd_info *dhd, void *data); +#endif int dhd_msg_level; + + +#include <wl_iw.h> + char fw_path[MOD_PARAM_PATHLEN]; char nv_path[MOD_PARAM_PATHLEN]; +#ifdef SOFTAP +char fw_path2[MOD_PARAM_PATHLEN]; +#endif + /* Last connection success/failure status */ uint32 dhd_conn_event; uint32 dhd_conn_status; uint32 dhd_conn_reason; +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +extern int dhd_iscan_request(void * dhdp, uint16 action); +extern void dhd_ind_scan_confirm(void *h, bool status); +extern int dhd_iscan_in_progress(void *h); +void dhd_iscan_lock(void); +void dhd_iscan_unlock(void); +extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif +#if !ISPOWEROF2(DHD_SDALIGN) +#error DHD_SDALIGN is not a power of 2! +#endif + #ifdef DHD_DEBUG const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " __DATE__ " at " __TIME__; @@ -57,6 +99,7 @@ const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; void dhd_set_timer(void *bus, uint wdtick); + /* IOVar table */ enum { IOV_VERSION = 1, @@ -71,6 +114,21 @@ enum { IOV_LOGSTAMP, IOV_GPIOOB, IOV_IOCTLTIMEOUT, + IOV_HCI_CMD, /* HCI command */ + IOV_HCI_ACL_DATA, /* HCI data packet */ +#if defined(DHD_DEBUG) + IOV_CONS, + IOV_DCONSOLE_POLL, +#endif /* defined(DHD_DEBUG) */ +#ifdef PROP_TXSTATUS + IOV_PROPTXSTATUS_ENABLE, + IOV_PROPTXSTATUS_MODE, +#endif + IOV_BUS_TYPE, +#ifdef WLMEDIA_HTSF + IOV_WLPKTDLYSTAT_SZ, +#endif + IOV_CHANGEMTU, IOV_LAST }; @@ -78,30 +136,93 @@ 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 }, {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, +#ifdef DHD_DEBUG + {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, + {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, +#endif {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, + {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, + {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, +#ifdef PROP_TXSTATUS + {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, + /* + set the proptxtstatus operation mode: + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + */ + {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, +#endif + {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, +#ifdef WLMEDIA_HTSF + {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, +#endif + {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, {NULL, 0, 0, 0, 0 } }; - -void -dhd_common_init(void) +struct dhd_cmn * +dhd_common_init(osl_t *osh) { + dhd_cmn_t *cmn; + /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization * of globals as part of the declaration results in non-deterministic - * behaviour since the value of the globals may be different on the + * behavior since the value of the globals may be different on the * first time that the driver is initialized vs subsequent initializations. */ dhd_msg_level = DHD_ERROR_VAL; + /* Allocate private bus interface state */ + if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) { + DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__)); + return NULL; + } + memset(cmn, 0, sizeof(dhd_cmn_t)); + cmn->osh = osh; + +#ifdef CONFIG_BCM4329_FW_PATH + bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); +#else /* CONFIG_BCM4329_FW_PATH */ fw_path[0] = '\0'; +#endif /* CONFIG_BCM4329_FW_PATH */ +#ifdef CONFIG_BCM4329_NVRAM_PATH + bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1); +#else /* CONFIG_BCM4329_NVRAM_PATH */ nv_path[0] = '\0'; +#endif /* CONFIG_BCM4329_NVRAM_PATH */ +#ifdef SOFTAP + fw_path2[0] = '\0'; +#endif + return cmn; +} + +void +dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn) +{ + osl_t *osh; + dhd_cmn_t *cmn; + + if (dhd_pub != NULL) + cmn = dhd_pub->cmn; + else + cmn = sa_cmn; + + if (!cmn) + return; + + osh = cmn->osh; + + if (dhd_pub != NULL) + dhd_pub->cmn = NULL; + MFREE(osh, cmn, sizeof(dhd_cmn_t)); } static int @@ -141,8 +262,8 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped, dhdp->rx_flushed); + bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", + dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", dhdp->rx_readahead_cnt, dhdp->tx_realloc); bcm_bprintf(strbuf, "\n"); @@ -157,14 +278,43 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) return (!strbuf->size ? BCME_BUFTOOSHORT : 0); } +int +dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) +{ + wl_ioctl_t ioc; + + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + + return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); +} + + +int +dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) +{ + int ret; + + dhd_os_proto_block(dhd_pub); + + ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); + + + dhd_os_proto_unblock(dhd_pub); + return ret; +} + static int -dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, - const char *name, void *params, int plen, void *arg, int len, int val_size) +dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, + void *params, int plen, void *arg, int len, int val_size) { int bcmerror = 0; int32 int_val = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) goto exit; @@ -175,7 +325,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, switch (actionid) { case IOV_GVAL(IOV_VERSION): /* Need to have checked buffer length */ - strncpy((char*)arg, dhd_version, len); + bcm_strncpy_s((char*)arg, len, dhd_version, len); break; case IOV_GVAL(IOV_MSGLEVEL): @@ -186,9 +336,8 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, case IOV_SVAL(IOV_MSGLEVEL): dhd_msg_level = int_val; break; - case IOV_GVAL(IOV_BCMERRORSTR): - strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); + bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ((char *)arg)[BCME_STRLEN - 1] = 0x00; break; @@ -214,6 +363,22 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, bcmerror = dhd_dump(dhd_pub, arg, len); break; +#ifdef DHD_DEBUG + case IOV_GVAL(IOV_DCONSOLE_POLL): + int_val = (int32)dhd_console_ms; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DCONSOLE_POLL): + dhd_console_ms = (uint)int_val; + break; + + case IOV_SVAL(IOV_CONS): + if (len > 0) + bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); + break; +#endif /* DHD_DEBUG */ + case IOV_SVAL(IOV_CLEARCOUNTS): dhd_pub->tx_packets = dhd_pub->rx_packets = 0; dhd_pub->tx_errors = dhd_pub->rx_errors = 0; @@ -222,21 +387,36 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, dhd_pub->rx_dropped = 0; dhd_pub->rx_readahead_cnt = 0; dhd_pub->tx_realloc = 0; - dhd_pub->rx_flushed = 0; + dhd_pub->wd_dpc_sched = 0; memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); dhd_bus_clearcounts(dhd_pub); +#ifdef PROP_TXSTATUS + /* clear proptxstatus related counters */ + if (dhd_pub->wlfc_state) { + athost_wl_status_info_t *wlfc = + (athost_wl_status_info_t*)dhd_pub->wlfc_state; + wlfc_hanger_t* hanger; + + memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); + + hanger = (wlfc_hanger_t*)wlfc->hanger; + hanger->pushed = 0; + hanger->popped = 0; + hanger->failed_slotfind = 0; + hanger->failed_to_pop = 0; + hanger->failed_to_push = 0; + } +#endif /* PROP_TXSTATUS */ break; - case IOV_GVAL(IOV_IOCTLTIMEOUT): - { + case IOV_GVAL(IOV_IOCTLTIMEOUT): { int_val = (int32)dhd_os_get_ioctl_resp_timeout(); bcopy(&int_val, arg, sizeof(int_val)); break; } - case IOV_SVAL(IOV_IOCTLTIMEOUT): - { + case IOV_SVAL(IOV_IOCTLTIMEOUT): { if (int_val <= 0) bcmerror = BCME_BADARG; else @@ -244,6 +424,88 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, break; } + case IOV_SVAL(IOV_HCI_CMD): { + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; + + /* sanity check: command preamble present */ + if (len < HCI_CMD_PREAMBLE_SIZE) + return BCME_BUFTOOSHORT; + + /* sanity check: command parameters are present */ + if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) + return BCME_BUFTOOSHORT; + + dhd_bta_docmd(dhd_pub, cmd, len); + break; + } + + case IOV_SVAL(IOV_HCI_ACL_DATA): { + amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; + + /* sanity check: HCI header present */ + if (len < HCI_ACL_DATA_PREAMBLE_SIZE) + return BCME_BUFTOOSHORT; + + /* sanity check: ACL data is present */ + if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) + return BCME_BUFTOOSHORT; + + dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); + break; + } + +#ifdef PROP_TXSTATUS + case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): + int_val = dhd_pub->wlfc_enabled? 1 : 0; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): + dhd_pub->wlfc_enabled = int_val? 1 : 0; + break; + + case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { + athost_wl_status_info_t *wlfc = + (athost_wl_status_info_t*)dhd_pub->wlfc_state; + int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; + bcopy(&int_val, arg, val_size); + break; + } + + case IOV_SVAL(IOV_PROPTXSTATUS_MODE): + if (dhd_pub->wlfc_state) { + athost_wl_status_info_t *wlfc = + (athost_wl_status_info_t*)dhd_pub->wlfc_state; + wlfc->proptxstatus_mode = int_val & 0xff; + } + break; +#endif /* PROP_TXSTATUS */ + + case IOV_GVAL(IOV_BUS_TYPE): + /* The dhd application query the driver to check if its usb or sdio. */ +#ifdef BCMDHDUSB + int_val = BUS_TYPE_USB; +#endif + int_val = BUS_TYPE_SDIO; + bcopy(&int_val, arg, val_size); + break; + + +#ifdef WLMEDIA_HTSF + case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): + int_val = dhd_pub->htsfdlystat_sz; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): + dhd_pub->htsfdlystat_sz = int_val & 0xff; + printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); + break; +#endif + case IOV_SVAL(IOV_CHANGEMTU): + int_val &= 0xffff; + bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); + break; default: bcmerror = BCME_UNSUPPORTED; @@ -251,11 +513,13 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, } exit: + DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); return bcmerror; } /* Store the status of a connection attempt for later retrieval by an iovar */ -void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) +void +dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) { /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID * because an encryption/rsn mismatch results in both events, and @@ -269,9 +533,55 @@ void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) } } +bool +dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) +{ + void *p; + int eprec = -1; /* precedence to evict from */ + bool discard_oldest; + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(q, prec) && !pktq_full(q)) { + pktq_penq(q, prec, pkt); + return TRUE; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(q, prec)) + eprec = prec; + else if (pktq_full(q)) { + p = pktq_peek_tail(q, &eprec); + ASSERT(p); + if (eprec > prec) + return FALSE; + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + ASSERT(!pktq_pempty(q, eprec)); + discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); + if (eprec == prec && !discard_oldest) + return FALSE; /* refuse newer (incoming) packet */ + /* Evict packet according to discard policy */ + p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); + ASSERT(p); + + PKTFREE(dhdp->osh, p, TRUE); + } + + /* Enqueue */ + p = pktq_penq(q, prec, pkt); + ASSERT(p); + + return TRUE; +} + static int dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, - void *params, int plen, void *arg, int len, bool set) + void *params, int plen, void *arg, int len, bool set) { int bcmerror = 0; int val_size; @@ -289,14 +599,13 @@ dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, /* Set does NOT take qualifiers */ ASSERT(!set || (!params && !plen)); - if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) - { + if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { bcmerror = BCME_UNSUPPORTED; goto exit; } DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); + name, (set ? "set" : "get"), len, plen)); /* set up 'params' pointer in case this is a set command so that * the convenience int and bool code can be common to set and get @@ -315,6 +624,7 @@ dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, val_size = sizeof(int); actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); + bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); exit: @@ -328,6 +638,10 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (!buf) { + return BCME_BADARG; + } + switch (ioc->cmd) { case DHD_GET_MAGIC: if (buflen < sizeof(int)) @@ -349,7 +663,8 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) uint arglen; /* scan past the name to any arguments */ - for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--); + for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) + ; if (*arg) { bcmerror = BCME_BUFTOOSHORT; @@ -379,12 +694,13 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) break; /* if still not found, try bus module */ - if (ioc->cmd == DHD_GET_VAR) + if (ioc->cmd == DHD_GET_VAR) { bcmerror = dhd_bus_iovar_op(dhd_pub, buf, arg, arglen, buf, buflen, IOV_GET); - else + } else { bcmerror = dhd_bus_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); + } break; } @@ -396,78 +712,16 @@ dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) return bcmerror; } -#ifdef APSTA_PINGTEST -struct ether_addr guest_eas[MAX_GUEST]; -#endif - #ifdef SHOW_EVENTS static void wl_show_host_event(wl_event_msg_t *event, void *event_data) { uint i, status, reason; bool group = FALSE, flush_txq = FALSE, link = FALSE; - char *auth_str, *event_name; + const char *auth_str; + const char *event_name; uchar *buf; char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - static struct {uint event; char *event_name;} event_names[] = { - {WLC_E_SET_SSID, "SET_SSID"}, - {WLC_E_JOIN, "JOIN"}, - {WLC_E_START, "START"}, - {WLC_E_AUTH, "AUTH"}, - {WLC_E_AUTH_IND, "AUTH_IND"}, - {WLC_E_DEAUTH, "DEAUTH"}, - {WLC_E_DEAUTH_IND, "DEAUTH_IND"}, - {WLC_E_ASSOC, "ASSOC"}, - {WLC_E_ASSOC_IND, "ASSOC_IND"}, - {WLC_E_REASSOC, "REASSOC"}, - {WLC_E_REASSOC_IND, "REASSOC_IND"}, - {WLC_E_DISASSOC, "DISASSOC"}, - {WLC_E_DISASSOC_IND, "DISASSOC_IND"}, - {WLC_E_QUIET_START, "START_QUIET"}, - {WLC_E_QUIET_END, "END_QUIET"}, - {WLC_E_BEACON_RX, "BEACON_RX"}, - {WLC_E_LINK, "LINK"}, - {WLC_E_MIC_ERROR, "MIC_ERROR"}, - {WLC_E_NDIS_LINK, "NDIS_LINK"}, - {WLC_E_ROAM, "ROAM"}, - {WLC_E_TXFAIL, "TXFAIL"}, - {WLC_E_PMKID_CACHE, "PMKID_CACHE"}, - {WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, - {WLC_E_PRUNE, "PRUNE"}, - {WLC_E_AUTOAUTH, "AUTOAUTH"}, - {WLC_E_EAPOL_MSG, "EAPOL_MSG"}, - {WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, - {WLC_E_ADDTS_IND, "ADDTS_IND"}, - {WLC_E_DELTS_IND, "DELTS_IND"}, - {WLC_E_BCNSENT_IND, "BCNSENT_IND"}, - {WLC_E_BCNRX_MSG, "BCNRX_MSG"}, - {WLC_E_BCNLOST_MSG, "BCNLOST_MSG"}, - {WLC_E_ROAM_PREP, "ROAM_PREP"}, - {WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, - {WLC_E_PFN_NET_LOST, "PNO_NET_LOST"}, - {WLC_E_RESET_COMPLETE, "RESET_COMPLETE"}, - {WLC_E_JOIN_START, "JOIN_START"}, - {WLC_E_ROAM_START, "ROAM_START"}, - {WLC_E_ASSOC_START, "ASSOC_START"}, - {WLC_E_IBSS_ASSOC, "IBSS_ASSOC"}, - {WLC_E_RADIO, "RADIO"}, - {WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, - {WLC_E_PROBREQ_MSG, "PROBREQ_MSG"}, - {WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, - {WLC_E_PSK_SUP, "PSK_SUP"}, - {WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, - {WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, - {WLC_E_ICV_ERROR, "ICV_ERROR"}, - {WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, - {WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, - {WLC_E_TRACE, "TRACE"}, - {WLC_E_ACTION_FRAME, "ACTION FRAME"}, - {WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, - {WLC_E_IF, "IF"}, - {WLC_E_RSSI, "RSSI"}, - {WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} - }; - uint event_type, flags, auth_type, datalen; event_type = ntoh32(event->event_type); @@ -487,10 +741,9 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) (uchar)event->addr.octet[5]&0xff); event_name = "UNKNOWN"; - for (i = 0; i < ARRAYSIZE(event_names); i++) { - if (event_names[i].event == event_type) - event_name = event_names[i].event_name; - } + for (i = 0; i < (uint)bcmevent_names_size; i++) + if (bcmevent_names[i].event == event_type) + event_name = bcmevent_names[i].name; if (flags & WLC_EVENT_MSG_LINK) link = TRUE; @@ -508,16 +761,7 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_ASSOC_IND: case WLC_E_REASSOC_IND: -#ifdef APSTA_PINGTEST - { - int i; - for (i = 0; i < MAX_GUEST; ++i) - if (ETHER_ISNULLADDR(&guest_eas[i])) - break; - if (i < MAX_GUEST) - bcopy(event->addr.octet, guest_eas[i].octet, ETHER_ADDR_LEN); - } -#endif /* APSTA_PINGTEST */ + DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); break; @@ -538,18 +782,6 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: -#ifdef APSTA_PINGTEST - { - int i; - for (i = 0; i < MAX_GUEST; ++i) { - if (bcmp(guest_eas[i].octet, event->addr.octet, - ETHER_ADDR_LEN) == 0) { - bzero(guest_eas[i].octet, ETHER_ADDR_LEN); - break; - } - } - } -#endif /* APSTA_PINGTEST */ DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); break; @@ -631,6 +863,8 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) case WLC_E_PFN_NET_FOUND: case WLC_E_PFN_NET_LOST: case WLC_E_PFN_SCAN_COMPLETE: + case WLC_E_PFN_SCAN_NONE: + case WLC_E_PFN_SCAN_ALLGONE: DHD_EVENT(("PNOEVENT: %s\n", event_name)); break; @@ -640,56 +874,61 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) event_name, (int)status, (int)reason)); break; - case WLC_E_TRACE: - { - static uint32 seqnum_prev = 0; - msgtrace_hdr_t hdr; - uint32 nblost; - char *s, *p; - - buf = (uchar *) event_data; - memcpy(&hdr, buf, MSGTRACE_HDRLEN); - - if (hdr.version != MSGTRACE_VERSION) { - printf("\nMACEVENT: %s [unsupported version --> " - "dhd version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - /* There are 2 bytes available at the end of data */ - buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; +#ifdef WIFI_ACT_FRAME + case WLC_E_ACTION_FRAME: + DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); + break; +#endif /* WIFI_ACT_FRAME */ - if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { - printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); - } + case WLC_E_TRACE: { + static uint32 seqnum_prev = 0; + msgtrace_hdr_t hdr; + uint32 nblost; + char *s, *p; - nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) { - printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost); - } - seqnum_prev = ntoh32(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - p = &(buf[MSGTRACE_HDRLEN]); - while ((s = strstr(p, "\n")) != NULL) { - *s = '\0'; - printf("%s\n", p); - p = s+1; - } - printf("%s\n", p); + buf = (uchar *) event_data; + memcpy(&hdr, buf, MSGTRACE_HDRLEN); + if (hdr.version != MSGTRACE_VERSION) { + printf("\nMACEVENT: %s [unsupported version --> " + "dhd version:%d dongle version:%d]\n", + event_name, MSGTRACE_VERSION, hdr.version); /* Reset datalen to avoid display below */ datalen = 0; + break; + } + + /* There are 2 bytes available at the end of data */ + buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; + + if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { + printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" + "discarded_bytes %d discarded_printf %d]\n", + ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); + } + + nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; + if (nblost > 0) { + printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", + ntoh32(hdr.seqnum), nblost); + } + seqnum_prev = ntoh32(hdr.seqnum); + + /* Display the trace buffer. Advance from \n to \n to avoid display big + * printf (issue with Linux printk ) + */ + p = (char *)&buf[MSGTRACE_HDRLEN]; + while ((s = strstr(p, "\n")) != NULL) { + *s = '\0'; + printf("%s\n", p); + p = s+1; } + printf("%s\n", p); + + /* Reset datalen to avoid display below */ + datalen = 0; break; + } case WLC_E_RSSI: @@ -715,22 +954,26 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) #endif /* SHOW_EVENTS */ int -wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, +wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, wl_event_msg_t *event, void **data_ptr) { /* check whether packet is a BRCM event pkt */ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; char *event_data; - uint32 type, status; + uint32 type, status, reason, datalen; uint16 flags; + int evlen; - - if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) + if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { + DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); return (BCME_ERROR); + } /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ - if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) + if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { + DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); return (BCME_ERROR); + } *data_ptr = &pvt_data[1]; event_data = *data_ptr; @@ -741,52 +984,118 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, type = ntoh32_ua((void *)&event->event_type); flags = ntoh16_ua((void *)&event->flags); status = ntoh32_ua((void *)&event->status); + reason = ntoh32_ua((void *)&event->reason); + datalen = ntoh32_ua((void *)&event->datalen); + evlen = datalen + sizeof(bcm_event_t); + switch (type) { - case WLC_E_IF: - { - dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; - - printf("WLC_E_IF: ifevent->action = %d\n", ifevent->action); - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) - { - if (ifevent->action == WLC_E_IF_ADD) - dhd_add_if(dhd, ifevent->ifidx, - NULL, event->ifname, - pvt_data->eth.ether_dhost); - else - dhd_del_if(dhd, ifevent->ifidx); - } else { - DHD_ERROR(("%s: Invalid ifidx %d for %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); - } - } - break; -#ifdef P2P - case WLC_E_NDIS_LINK: - break; +#ifdef PROP_TXSTATUS + case WLC_E_FIFO_CREDIT_MAP: + dhd_wlfc_event(dhd_pub->info); + dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); + WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " + "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], + event_data[2], + event_data[3], event_data[4], event_data[5])); + break; #endif - case WLC_E_LINK: - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - /* Fall thru and continue */ - default: - *ifidx = dhd_ifname2idx(dhd, event->ifname); - DHD_EVENT(("%s: event %d, idx %d\n", __FUNCTION__, type, *ifidx)); + + case WLC_E_IF: + { + dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; +#ifdef PROP_TXSTATUS +{ + uint8* ea = pvt_data->eth.ether_dhost; + WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " + "[%02x:%02x:%02x:%02x:%02x:%02x]\n", + ifevent->ifidx, + ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), + ((ifevent->is_AP == 0) ? "STA":"AP "), + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); + (void)ea; + + dhd_wlfc_interface_event(dhd_pub->info, + ((ifevent->action == WLC_E_IF_ADD) ? + eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), + ifevent->ifidx, ifevent->is_AP, ea); + + /* dhd already has created an interface by default, for 0 */ + if (ifevent->ifidx == 0) + break; +} +#endif /* PROP_TXSTATUS */ + + if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { + if (ifevent->action == WLC_E_IF_ADD) + dhd_add_if(dhd_pub->info, ifevent->ifidx, + NULL, event->ifname, + event->addr.octet, + ifevent->flags, ifevent->bssidx); + else + dhd_del_if(dhd_pub->info, ifevent->ifidx); + } else { +#ifndef PROP_TXSTATUS + DHD_ERROR(("%s: Invalid ifidx %d for %s\n", + __FUNCTION__, ifevent->ifidx, event->ifname)); +#endif /* !PROP_TXSTATUS */ + } + } + /* send up the if event: btamp user needs it */ + *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); break; + + +#ifdef WLMEDIA_HTSF + case WLC_E_HTSFSYNC: + htsf_update(dhd_pub->info, event_data); + break; +#endif /* WLMEDIA_HTSF */ + case WLC_E_NDIS_LINK: { + uint32 temp = hton32(WLC_E_LINK); + + memcpy((void *)(&pvt_data->event.event_type), &temp, + sizeof(pvt_data->event.event_type)); + } + /* These are what external supplicant/authenticator wants */ + /* fall through */ + case WLC_E_LINK: + case WLC_E_DEAUTH: + case WLC_E_DEAUTH_IND: + case WLC_E_DISASSOC: + case WLC_E_DISASSOC_IND: + DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + /* fall through */ + default: + *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); + /* push up to external supp/auth */ + dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); + DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + + /* put it back to WLC_E_NDIS_LINK */ + if (type == WLC_E_NDIS_LINK) { + uint32 temp; + + temp = ntoh32_ua((void *)&event->event_type); + DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); + + temp = ntoh32(WLC_E_NDIS_LINK); + memcpy((void *)(&pvt_data->event.event_type), &temp, + sizeof(pvt_data->event.event_type)); + } + break; } #ifdef SHOW_EVENTS - wl_show_host_event(event, event_data); + wl_show_host_event(event, (void *)event_data); #endif /* SHOW_EVENTS */ return (BCME_OK); } - void wl_event_to_host_order(wl_event_msg_t * evt) { @@ -802,18 +1111,1170 @@ wl_event_to_host_order(wl_event_msg_t * evt) evt->version = ntoh16(evt->version); } +void +dhd_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"); +} + +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) + +/* Convert user's input in hex pattern to byte-size mask */ +static int +wl_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + bcm_strncpy_s(num, sizeof(num), src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +void +dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) +{ + char *argv[8]; + int i = 0; + const char *str; + int buf_len; + int str_len; + char *arg_save = 0, *arg_org = 0; + int rc; + char buf[128]; + wl_pkt_filter_enable_t enable_parm; + wl_pkt_filter_enable_t * pkt_filterp; + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + arg_org = arg_save; + memcpy(arg_save, arg, strlen(arg) + 1); + + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_enable"; + str_len = strlen(str); + bcm_strncpy_s(buf, sizeof(buf), str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); + + /* Parse packet filter id. */ + enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); + + /* Parse enable/disable value. */ + enable_parm.enable = htod32(enable); + + buf_len += sizeof(enable_parm); + memcpy((char *)pkt_filterp, + &enable_parm, + sizeof(enable_parm)); + + /* Enable/disable the specified filter. */ + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + + /* Contorl the master mode */ + bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + rc = rc >= 0 ? 0 : rc; + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); +} + +void +dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) +{ + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + int rc; + uint32 mask_size; + uint32 pattern_size; + char *argv[8], * buf = 0; + int i = 0; + char *arg_save = 0, *arg_org = 0; +#define BUF_SIZE 2048 + + if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + + arg_org = arg_save; + + if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { + DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); + goto fail; + } + + memcpy(arg_save, arg, strlen(arg) + 1); + + if (strlen(arg) > BUF_SIZE) { + DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); + goto fail; + } + + argv[i] = bcmstrtok(&arg_save, " ", 0); + while (argv[i++]) + argv[i] = bcmstrtok(&arg_save, " ", 0); + + i = 0; + if (argv[i] == NULL) { + DHD_ERROR(("No args provided\n")); + goto fail; + } + + str = "pkt_filter_add"; + str_len = strlen(str); + bcm_strncpy_s(buf, BUF_SIZE, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Polarity not provided\n")); + goto fail; + } + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Filter type not provided\n")); + goto fail; + } + + /* Parse filter type. */ + pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Offset not provided\n")); + goto fail; + } + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Bitmask not provided\n")); + goto fail; + } + + /* Parse pattern filter mask. */ + mask_size = + htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); + + if (argv[++i] == NULL) { + DHD_ERROR(("Pattern not provided\n")); + goto fail; + } + + /* Parse pattern filter pattern. */ + pattern_size = + htod32(wl_pattern_atoh(argv[i], + (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + DHD_ERROR(("Mask and pattern not the same size\n")); + goto fail; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local variable (keep_alive_pkt), and + ** then memcpy'ed into buffer (keep_alive_pktp) since there is no + ** guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, + &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + rc = rc >= 0 ? 0 : rc; + + if (rc) + DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", + __FUNCTION__, arg, rc)); + else + DHD_TRACE(("%s: successfully added pktfilter %s\n", + __FUNCTION__, arg)); + +fail: + if (arg_org) + MFREE(dhd->osh, arg_org, strlen(arg) + 1); + + if (buf) + MFREE(dhd->osh, buf, BUF_SIZE); +} + +void +dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) +{ + char iovbuf[32]; + int retcode; + + bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", + __FUNCTION__, arp_mode, retcode)); + else + DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", + __FUNCTION__, arp_mode)); +} + +void +dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) +{ + char iovbuf[32]; + int retcode; + + bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", + __FUNCTION__, arp_enable, retcode)); + else + DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", + __FUNCTION__, arp_enable)); +} + +int +dhd_preinit_ioctls(dhd_pub_t *dhd) +{ + int ret = 0; + char eventmask[WL_EVENTING_MASK_LEN]; + char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ + + uint up = 0; + uint power_mode = PM_FAST; + uint32 dongle_align = DHD_SDALIGN; + uint32 glom = 0; + int arpoe = 1; + int arp_ol = 0xf; + int scan_assoc_time = 40; + int scan_unassoc_time = 80; + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + uint32 mask_size; + uint32 pattern_size; + char buf[256]; + char *ptr; + uint filter_mode = 1; + uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ +#ifdef AP + uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ + uint32 apsta = 1; /* Enable APSTA mode */ +#endif + + /* Get the device MAC address */ + strcpy(iovbuf, "cur_etheraddr"); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { + DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); + return BCME_NOTUP; + } + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); + + /* Set Country code */ + if (dhd->dhd_cspec.ccode[0] != 0) { + bcm_mkiovar("country", (char *)&dhd->dhd_cspec, + sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); + } + + /* Set Listen Interval */ + bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); + + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + ptr = buf; + bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); + dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), TRUE, 0); + bcmstrtok(&ptr, "\n", 0); + /* Print fw version info */ + DHD_ERROR(("Firmware version = %s\n", buf)); + + /* Set PowerSave mode */ + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); + + /* Match Host and Dongle rx alignment */ + bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* disable glom option per default */ + bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + +#ifdef AP + /* Turn off MPC in AP mode */ + bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* Enable APSTA mode */ + bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif + + /* Force STA UP */ + ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0); + if (ret < 0) + goto done; + + /* Setup event_msgs */ + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + if (ret < 0) + goto done; + bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); + + /* Setup event_msgs */ + setbit(eventmask, WLC_E_SET_SSID); + setbit(eventmask, WLC_E_PRUNE); + setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_REASSOC); + setbit(eventmask, WLC_E_REASSOC_IND); + setbit(eventmask, WLC_E_DEAUTH_IND); + setbit(eventmask, WLC_E_DISASSOC_IND); + setbit(eventmask, WLC_E_DISASSOC); + setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_ASSOC_IND); + setbit(eventmask, WLC_E_PSK_SUP); + setbit(eventmask, WLC_E_LINK); + setbit(eventmask, WLC_E_NDIS_LINK); + setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_PMKID_CACHE); + setbit(eventmask, WLC_E_TXFAIL); + setbit(eventmask, WLC_E_JOIN_START); + setbit(eventmask, WLC_E_SCAN_COMPLETE); +#ifdef WLMEDIA_HTSF + setbit(eventmask, WLC_E_HTSFSYNC); +#endif + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, + sizeof(scan_assoc_time), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, + sizeof(scan_unassoc_time), TRUE, 0); + + /* Set ARP offload */ + bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* add a default packet filter pattern */ + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(100); + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(0); + + /* Parse filter type. */ + pkt_filter.type = htod32(0); + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(0); + + /* Parse pattern filter mask. */ + mask_size = htod32(wl_pattern_atoh("0x01", + (char *) pkt_filterp->u.pattern.mask_and_pattern)); + + /* Parse pattern filter pattern. */ + pattern_size = htod32(wl_pattern_atoh("0x00", + (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + DHD_ERROR(("Mask and pattern not the same size\n")); + return -EINVAL; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local variable (keep_alive_pkt), and + ** then memcpy'ed into buffer (keep_alive_pktp) since there is no + ** guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); + + /* set mode to allow pattern */ + bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + +done: + return ret; +} /* send up locally generated event */ void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) { switch (ntoh32(event->event_type)) { - + case WLC_E_BTA_HCI_EVENT: + break; default: break; } - /* Call per-port handler. */ dhd_sendup_event(dhdp, event, data); } + + + +#ifdef SIMPLE_ISCAN + +uint iscan_thread_id = 0; +iscan_buf_t * iscan_chain = 0; + +iscan_buf_t * +dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf) +{ + iscan_buf_t *iscanbuf_alloc = 0; + iscan_buf_t *iscanbuf_head; + + DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); + dhd_iscan_lock(); + + iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t)); + if (iscanbuf_alloc == NULL) + goto fail; + + iscanbuf_alloc->next = NULL; + iscanbuf_head = *iscanbuf; + + DHD_ISCAN(("%s: addr of allocated node = 0x%X" + "addr of iscanbuf_head = 0x%X dhd = 0x%X\n", + __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd)); + + if (iscanbuf_head == NULL) { + *iscanbuf = iscanbuf_alloc; + DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__)); + goto fail; + } + + while (iscanbuf_head->next) + iscanbuf_head = iscanbuf_head->next; + + iscanbuf_head->next = iscanbuf_alloc; + +fail: + dhd_iscan_unlock(); + return iscanbuf_alloc; +} + +void +dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) +{ + iscan_buf_t *iscanbuf_free = 0; + iscan_buf_t *iscanbuf_prv = 0; + iscan_buf_t *iscanbuf_cur; + dhd_pub_t *dhd = dhd_bus_pub(dhdp); + DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); + + dhd_iscan_lock(); + + iscanbuf_cur = iscan_chain; + + /* If iscan_delete is null then delete the entire + * chain or else delete specific one provided + */ + if (!iscan_delete) { + while (iscanbuf_cur) { + iscanbuf_free = iscanbuf_cur; + iscanbuf_cur = iscanbuf_cur->next; + iscanbuf_free->next = 0; + MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t)); + } + iscan_chain = 0; + } else { + while (iscanbuf_cur) { + if (iscanbuf_cur == iscan_delete) + break; + iscanbuf_prv = iscanbuf_cur; + iscanbuf_cur = iscanbuf_cur->next; + } + if (iscanbuf_prv) + iscanbuf_prv->next = iscan_delete->next; + + iscan_delete->next = 0; + MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t)); + + if (!iscanbuf_prv) + iscan_chain = 0; + } + dhd_iscan_unlock(); +} + +iscan_buf_t * +dhd_iscan_result_buf(void) +{ + return iscan_chain; +} + +int +dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size) +{ + int rc = -1; + dhd_pub_t *dhd = dhd_bus_pub(dhdp); + char *buf; + char iovar[] = "iscan"; + uint32 allocSize = 0; + wl_ioctl_t ioctl; + + if (pParams) { + allocSize = (size + strlen(iovar) + 1); + if ((allocSize < size) || (allocSize < strlen(iovar))) + { + DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n", + __FUNCTION__, allocSize, size, strlen(iovar))); + goto cleanUp; + } + buf = MALLOC(dhd->osh, allocSize); + + if (buf == NULL) + { + DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize)); + goto cleanUp; + } + ioctl.cmd = WLC_SET_VAR; + bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize); + rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize); + } + +cleanUp: + if (buf) { + MFREE(dhd->osh, buf, allocSize); + } + + return rc; +} + +static int +dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) +{ + wl_iscan_results_t *list_buf; + wl_iscan_results_t list; + wl_scan_results_t *results; + iscan_buf_t *iscan_cur; + int status = -1; + dhd_pub_t *dhd = dhd_bus_pub(dhdp); + int rc; + wl_ioctl_t ioctl; + + DHD_ISCAN(("%s: Enter\n", __FUNCTION__)); + + iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain); + if (!iscan_cur) { + DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__)); + dhd_iscan_free_buf(dhdp, 0); + dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT); + dhd_ind_scan_confirm(dhdp, FALSE); + goto fail; + } + + dhd_iscan_lock(); + + memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); + list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf; + results = &list_buf->results; + results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; + results->version = 0; + results->count = 0; + + memset(&list, 0, sizeof(list)); + list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); + bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE, + iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); + ioctl.cmd = WLC_GET_VAR; + ioctl.set = FALSE; + rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); + + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + *scan_count = results->count = dtoh32(results->count); + status = dtoh32(list_buf->status); + DHD_ISCAN(("%s: Got %d resuls\n", __FUNCTION__, results->count)); + + dhd_iscan_unlock(); + + if (!(*scan_count)) { + /* TODO: race condition when FLUSH already called */ + dhd_iscan_free_buf(dhdp, 0); + } +fail: + return status; +} + +#endif /* SIMPLE_ISCAN */ + +/* Function to estimate possible DTIM_SKIP value */ +int +dhd_get_dtim_skip(dhd_pub_t *dhd) +{ + int bcn_li_dtim; + char buf[128]; + int ret; + int dtim_assoc = 0; + + if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) + bcn_li_dtim = 3; + else + bcn_li_dtim = dhd->dtim_skip; + + /* Read DTIM value if associated */ + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("dtim_assoc", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0)) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + bcn_li_dtim = 1; + goto exit; + } + else + dtim_assoc = dtoh32(*(int *)buf); + + DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", + __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); + + /* if not assocated just eixt */ + if (dtim_assoc == 0) { + goto exit; + } + + /* check if sta listen interval fits into AP dtim */ + if (dtim_assoc > LISTEN_INTERVAL) { + /* AP DTIM to big for our Listen Interval : no dtim skiping */ + bcn_li_dtim = 1; + DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", + __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); + goto exit; + } + + if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { + /* Round up dtim_skip to fit into STAs Listen Interval */ + bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); + DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); + } + +exit: + return bcn_li_dtim; +} + + +#ifdef PNO_SUPPORT +int +dhd_pno_clean(dhd_pub_t *dhd) +{ + char iovbuf[128]; + int pfn_enabled = 0; + int iov_len = 0; + int ret; + + /* Disable pfn */ + iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { + /* clear pfn */ + iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); + if (iov_len) { + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + iov_len, TRUE, 0)) < 0) { + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + } + } + else { + ret = -1; + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); + } + } + else + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); + + return ret; +} + +int +dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) +{ + char iovbuf[128]; + uint8 bssid[6]; + int ret = -1; + + if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { + DHD_ERROR(("%s error exit\n", __FUNCTION__)); + return ret; + } + + memset(iovbuf, 0, sizeof(iovbuf)); + /* Check if disassoc to enable pno */ + if ((pfn_enabled) && + ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, + (char *)&bssid, ETHER_ADDR_LEN, TRUE, 0)) == BCME_NOTASSOCIATED)) { + DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__)); + } + else if (pfn_enabled) { + DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n", + __FUNCTION__, ret)); + return ret; + } + /* Enable/disable PNO */ + if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); + return ret; + } + else { + dhd->pno_enable = pfn_enabled; + DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable)); + } + } + else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); + + return ret; +} + +/* Function to execute combined scan */ +int +dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, + int pno_repeat, int pno_freq_expo_max) +{ + int err = -1; + char iovbuf[128]; + int k, i; + wl_pfn_param_t pfn_param; + wl_pfn_t pfn_element; + uint len = 0; + + DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); + + if ((!dhd) && (!ssids_local)) { + DHD_ERROR(("%s error exit\n", __FUNCTION__)); + err = -1; + } + + /* Check for broadcast ssid */ + for (k = 0; k < nssid; k++) { + if (!ssids_local[k].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); + return err; + } + } +/* #define PNO_DUMP 1 */ +#ifdef PNO_DUMP + { + int j; + for (j = 0; j < nssid; j++) { + DHD_ERROR(("%d: scan for %s size =%d\n", j, + ssids_local[j].SSID, ssids_local[j].SSID_len)); + } + } +#endif /* PNO_DUMP */ + + /* clean up everything */ + if ((err = dhd_pno_clean(dhd)) < 0) { + DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); + return err; + } + memset(&pfn_param, 0, sizeof(pfn_param)); + memset(&pfn_element, 0, sizeof(pfn_element)); + + /* set pfn parameters */ + pfn_param.version = htod32(PFN_VERSION); + pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); + + /* check and set extra pno params */ + if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { + pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); + pfn_param.repeat = htod32(pno_repeat); + pfn_param.exp = htod32(pno_freq_expo_max); + } + /* set up pno scan fr */ + if (scan_fr != 0) + pfn_param.scan_freq = htod32(scan_fr); + + if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { + DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC)); + return err; + } + if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { + DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); + return err; + } + len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0); + + /* set all pfn ssid */ + for (i = 0; i < nssid; i++) { + + pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); + pfn_element.auth = (DOT11_OPEN_SYSTEM); + pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); + pfn_element.wsec = htod32(0); + pfn_element.infra = htod32(1); + + memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); + pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; + + if ((len = + bcm_mkiovar("pfn_add", (char *)&pfn_element, + sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { + if ((err = + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { + DHD_ERROR(("%s failed for i=%d error=%d\n", + __FUNCTION__, i, err)); + return err; + } + else + DHD_ERROR(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", + __FUNCTION__, pfn_param.scan_freq, + pfn_param.repeat, pfn_param.exp)); + } + else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); + } + + /* Enable PNO */ + /* dhd_pno_enable(dhd, 1); */ + return err; +} + +int +dhd_pno_get_status(dhd_pub_t *dhd) +{ + int ret = -1; + + if (!dhd) + return ret; + else + return (dhd->pno_enable); +} + +#endif /* PNO_SUPPORT */ + +/* Android ComboSCAN support */ + +/* + * data parsing from ComboScan tlv list +*/ +int +wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, + int input_size, int *bytes_left) +{ + char* str = *list_str; + uint16 short_temp; + uint32 int_temp; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + /* Clean all dest bytes */ + memset(dst, 0, dst_size); + while (*bytes_left > 0) { + + if (str[0] != token) { + DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", + __FUNCTION__, token, str[0], *bytes_left)); + return -1; + } + + *bytes_left -= 1; + str += 1; + + if (input_size == 1) { + memcpy(dst, str, input_size); + } + else if (input_size == 2) { + memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), + input_size); + } + else if (input_size == 4) { + memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), + input_size); + } + + *bytes_left -= input_size; + str += input_size; + *list_str = str; + return 1; + } + return 1; +} + +/* + * channel list parsing from cscan tlv list +*/ +int +wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left) +{ + char* str = *list_str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { + *list_str = str; + DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* All channels */ + channel_list[idx] = 0x0; + } + else { + channel_list[idx] = (uint16)str[0]; + DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); + } + *bytes_left -= 1; + str += 1; + + if (idx++ > 255) { + DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* + * SSIDs list parsing from cscan tlv list + */ +int +wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) +{ + char* str = *list_str; + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + DHD_ERROR(("%s error paramters\n", __FUNCTION__)); + return -1; + } + + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); + *bytes_left -= 1; + str += 1; + + DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); + } + else if (str[0] <= DOT11_MAX_SSID_LEN) { + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + DHD_ERROR(("%s out of memory range len=%d but left=%d\n", + __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); + return -1; + } + + memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + + DHD_TRACE(("%s :size=%d left=%d\n", + (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); + } + else { + DHD_ERROR(("### SSID size more that %d\n", str[0])); + return -1; + } + + if (idx++ > max) { + DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); + return -1; + } + } + + *list_str = str; + return idx; +} + +/* Parse a comma-separated list from list_str into ssid array, starting + * at index idx. Max specifies size of the ssid array. Parses ssids + * and returns updated idx; if idx >= max not all fit, the excess have + * not been copied. Returns -1 on empty string, or on ssid too long. + */ +int +wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) +{ + char* str, *ptr; + + if ((list_str == NULL) || (*list_str == NULL)) + return -1; + + for (str = *list_str; str != NULL; str = ptr) { + + /* check for next TAG */ + if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { + *list_str = str + strlen(GET_CHANNEL); + return idx; + } + + if ((ptr = strchr(str, ',')) != NULL) { + *ptr++ = '\0'; + } + + if (strlen(str) > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); + return -1; + } + + if (strlen(str) == 0) + ssid[idx].SSID_len = 0; + + if (idx < max) { + bcm_strcpy_s((char*)ssid[idx].SSID, sizeof(ssid[idx].SSID), str); + ssid[idx].SSID_len = strlen(str); + } + idx++; + } + return idx; +} + +/* + * Parse channel list from iwpriv CSCAN + */ +int +wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) +{ + int num; + int val; + char* str; + char* endptr = NULL; + + if ((list_str == NULL)||(*list_str == NULL)) + return -1; + + str = *list_str; + num = 0; + while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { + val = (int)strtoul(str, &endptr, 0); + if (endptr == str) { + printf("could not parse channel number starting at" + " substring \"%s\" in list:\n%s\n", + str, *list_str); + return -1; + } + str = endptr + strspn(endptr, " ,"); + + if (num == channel_num) { + DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", + channel_num, *list_str)); + return -1; + } + + channel_list[num++] = (uint16)val; + } + *list_str = str; + return num; +} diff --git a/src/dhd/sys/dhd_custom_gpio.c b/src/dhd/sys/dhd_custom_gpio.c index 467a53b..ba60d91 100644 --- a/src/dhd/sys/dhd_custom_gpio.c +++ b/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-2011, 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.2.5 2009/09/30 22:01:55 Exp $ +* $Id: dhd_custom_gpio.c,v 1.2.42.1 2010-10-19 00:41:09 Exp $ */ #include <typedefs.h> @@ -41,6 +41,12 @@ extern void bcm_wlan_power_off(int); extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ +#if defined(CONFIG_MACH_MAHIMAHI) +int wifi_set_carddetect(int on); +int wifi_set_power(int on, unsigned long msec); +int wifi_get_irq_number(unsigned long *irq_flags_ptr); +int wifi_get_mac_addr(unsigned char *buf); +#endif #if defined(OOB_INTR_ONLY) @@ -48,15 +54,35 @@ extern void bcm_wlan_power_on(int); 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 */ +static int dhd_oob_gpio_num = -1; module_param(dhd_oob_gpio_num, int, 0644); MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); -int dhd_customer_oob_irq_map(void) +/* This function will return: + * 1) return : Host gpio interrupt number per customer platform + * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge + * + * NOTE : + * Customer should check his platform definitions + * and his Host Interrupt spec + * to figure out the proper setting for his platform. + * Broadcom provides just reference settings as example. + * + */ +int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) { -int host_oob_irq; + int host_oob_irq = 0; + +#ifdef CONFIG_MACH_MAHIMAHI + host_oob_irq = wifi_get_irq_number(irq_flags_ptr); + +#else /* for NOT CONFIG_MACH_MAHIMAHI */ #if defined(CUSTOM_OOB_GPIO_NUM) if (dhd_oob_gpio_num < 0) { dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; @@ -64,16 +90,23 @@ int host_oob_irq; #endif 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); +#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 /* CONFIG_MACH_MAHIMAHI */ + return (host_oob_irq); } #endif /* defined(OOB_INTR_ONLY) */ @@ -89,6 +122,9 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #ifdef CUSTOMER_HW bcm_wlan_power_off(2); #endif /* CUSTOMER_HW */ +#ifdef CONFIG_MACH_MAHIMAHI + wifi_set_power(0, 0); +#endif WL_ERROR(("=========== WLAN placed in RESET ========\n")); break; @@ -98,6 +134,9 @@ dhd_customer_gpio_wlan_ctrl(int onoff) #ifdef CUSTOMER_HW bcm_wlan_power_on(2); #endif /* CUSTOMER_HW */ +#ifdef CONFIG_MACH_MAHIMAHI + wifi_set_power(1, 0); +#endif WL_ERROR(("=========== WLAN going back to live ========\n")); break; @@ -116,7 +155,81 @@ dhd_customer_gpio_wlan_ctrl(int onoff) bcm_wlan_power_on(1); #endif /* CUSTOMER_HW */ /* Lets customer power to get stable */ - OSL_DELAY(500); + OSL_DELAY(200); break; } } + +#ifdef GET_CUSTOM_MAC_ENABLE +/* Function to get custom MAC address */ +int +dhd_custom_get_mac_address(unsigned char *buf) +{ + int ret = 0; + + WL_TRACE(("%s Enter\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + + /* Customer access to MAC address stored outside of DHD driver */ +#if defined(CONFIG_MACH_MAHIMAHI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + ret = wifi_get_mac_addr(buf); +#endif + +#ifdef EXAMPLE_GET_MAC + /* EXAMPLE code */ + { + struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; + bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); + } +#endif /* EXAMPLE_GET_MAC */ + + return ret; +} +#endif /* GET_CUSTOM_MAC_ENABLE */ + +/* Customized Locale table : OPTIONAL feature */ +const struct cntry_locales_custom translate_custom_table[] = { +/* Table should be filled out based on custom platform regulatory requirement */ +#ifdef EXAMPLE_TABLE + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 05}, /* input ISO "CA" to : US regrev 69 */ + {"FR", "EU", 05}, + {"DE", "EU", 05}, + {"IR", "EU", 05}, + {"UK", "EU", 05}, /* input ISO "UK" to : EU regrev 05 */ + {"KR", "XY", 03}, + {"AU", "XY", 03}, + {"CN", "XY", 03}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 03}, + {"AR", "XY", 03} +#endif /* EXMAPLE_TABLE */ +}; + + +/* Customized Locale convertor +* input : ISO 3166-1 country abbreviation +* output: customized cspec +*/ +void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) +{ + int size, i; + + size = ARRAYSIZE(translate_custom_table); + + if (cspec == 0) + return; + + if (size == 0) + return; + + for (i = 0; i < size; i++) { + if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { + memcpy(cspec->ccode, translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[i].custom_locale_rev; + break; + } + } + return; +} diff --git a/src/dhd/sys/dhd_dbg.h b/src/dhd/sys/dhd_dbg.h index c4a6e8e..8bbfc1e 100644 --- a/src/dhd/sys/dhd_dbg.h +++ b/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-2011, 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,15 +21,16 @@ * 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.28.3 2009/10/05 05:54:04 Exp $ + * $Id: dhd_dbg.h,v 1.9.6.1 2010-12-22 23:47:24 Exp $ */ #ifndef _dhd_dbg_ #define _dhd_dbg_ -#ifdef DHD_DEBUG +#if defined(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) @@ -41,6 +42,7 @@ #define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) #define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) #define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) +#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) #define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) #define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) @@ -54,10 +56,11 @@ #define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) #define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) #define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) +#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -#else /* DHD_DEBUG */ +#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ -#define DHD_ERROR(args) printf 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) @@ -69,6 +72,7 @@ #define DHD_GLOM(args) #define DHD_EVENT(args) #define DHD_BTA(args) +#define DHD_ISCAN(args) #define DHD_ERROR_ON() 0 #define DHD_TRACE_ON() 0 @@ -82,8 +86,8 @@ #define DHD_GLOM_ON() 0 #define DHD_EVENT_ON() 0 #define DHD_BTA_ON() 0 - -#endif /* DHD_DEBUG */ +#define DHD_ISCAN_ON() 0 +#endif #define DHD_LOG(args) diff --git a/src/dhd/sys/dhd_linux.c b/src/dhd/sys/dhd_linux.c index fc13371..cd835ce 100644 --- a/src/dhd/sys/dhd_linux.c +++ b/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-2011, 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,9 +22,12 @@ * 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.13.6.55 2009/10/13 01:28:33 Exp $ + * $Id: dhd_linux.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $ */ +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include <linux/platform_device.h> +#endif #include <typedefs.h> #include <linuxver.h> #include <osl.h> @@ -54,7 +57,180 @@ #include <dhd_bus.h> #include <dhd_proto.h> #include <dhd_dbg.h> +#ifdef CONFIG_HAS_WAKELOCK +#include <linux/wakelock.h> +#endif +#ifdef WL_CFG80211 +#include <wl_cfg80211.h> +#endif + +#include <proto/802.11_bta.h> +#include <proto/bt_amp_hci.h> +#include <dhd_bta.h> + +#ifdef WLMEDIA_HTSF +#include <linux/time.h> +#include <htsf.h> + +#define HTSF_MINLEN 200 /* min. packet length to timestamp */ +#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ +#define TSMAX 1000 /* max no. of timing record kept */ +#define NUMBIN 34 + +static uint32 tsidx = 0; +static uint32 htsf_seqnum = 0; + +uint32 tsfsync; +struct timeval tsync; +static uint32 tsport = 5010; + +typedef struct histo_ { + uint32 bin[NUMBIN]; +} histo_t; + +static histo_t vi_d1, vi_d2, vi_d3, vi_d4; +#endif /* WLMEDIA_HTSF */ + +#ifdef PROP_TXSTATUS +#include <wlfc_proto.h> +#include <dhd_wlfc.h> +#endif +#if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) +#include <linux/wlan_plat.h> +#else +#include <linux/wifi_tiwlan.h> +#endif + + +struct semaphore wifi_control_sem; +struct dhd_bus *g_bus; +static struct wifi_platform_data *wifi_control_data = NULL; +static struct resource *wifi_irqres = NULL; + +int wifi_get_irq_number(unsigned long *irq_flags_ptr) +{ + if (wifi_irqres) { + *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; + return (int)wifi_irqres->start; + } +#ifdef CUSTOM_OOB_GPIO_NUM + return CUSTOM_OOB_GPIO_NUM; +#else + return -1; +#endif +} + +int wifi_set_carddetect(int on) +{ + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_control_data && wifi_control_data->set_carddetect) { + wifi_control_data->set_carddetect(on); + } + return 0; +} + +int wifi_set_power(int on, unsigned long msec) +{ + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_control_data && wifi_control_data->set_power) { + wifi_control_data->set_power(on); + } + if (msec) + mdelay(msec); + return 0; +} + +int wifi_set_reset(int on, unsigned long msec) +{ + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_control_data && wifi_control_data->set_reset) { + wifi_control_data->set_reset(on); + } + if (msec) + mdelay(msec); + return 0; +} + +#if defined(CONFIG_MACH_MAHIMAHI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) +int wifi_get_mac_addr(unsigned char *buf) +{ + DHD_ERROR(("%s\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + if (wifi_control_data && wifi_control_data->get_mac_addr) { + return wifi_control_data->get_mac_addr(buf); + } + return -EOPNOTSUPP; +} +#endif /* defined (CONFIG_MACH_MAHIMAHI) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ + +static int wifi_probe(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *)(pdev->dev.platform_data); + + DHD_ERROR(("## %s\n", __FUNCTION__)); + wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); + wifi_control_data = wifi_ctrl; + + wifi_set_power(1, 0); /* Power On */ + wifi_set_carddetect(1); /* CardDetect (0->1) */ + + up(&wifi_control_sem); + return 0; +} + +static int wifi_remove(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *)(pdev->dev.platform_data); + + DHD_ERROR(("## %s\n", __FUNCTION__)); + wifi_control_data = wifi_ctrl; + + wifi_set_carddetect(0); /* CardDetect (1->0) */ + wifi_set_power(0, 0); /* Power Off */ + + up(&wifi_control_sem); + return 0; +} +static int wifi_suspend(struct platform_device *pdev, pm_message_t state) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); + return 0; +} +static int wifi_resume(struct platform_device *pdev) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); + return 0; +} + +static struct platform_driver wifi_device = { + .probe = wifi_probe, + .remove = wifi_remove, + .suspend = wifi_suspend, + .resume = wifi_resume, + .driver = { + .name = "bcm4329_wlan", + } +}; + +int wifi_add_dev(void) +{ + DHD_TRACE(("## Calling platform_driver_register\n")); + return platform_driver_register(&wifi_device); +} + +void wifi_del_dev(void) +{ + DHD_TRACE(("## Unregister platform_driver_register\n")); + platform_driver_unregister(&wifi_device); +} +#endif /* defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) #include <linux/suspend.h> @@ -69,6 +245,10 @@ extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ +#include <dhd_bus.h> + +#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) + #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) const char * print_tainted() @@ -78,9 +258,20 @@ print_tainted() #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ /* Linux wireless extension support */ -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) #include <wl_iw.h> -#endif /* CONFIG_WIRELESS_EXT */ +extern wl_iw_extra_params_t g_wl_iw_params; +#endif /* defined(CONFIG_WIRELESS_EXT) */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + +#ifdef PKT_FILTER_SUPPORT +extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); +extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); +#endif /* Interface control information */ typedef struct dhd_if { @@ -95,73 +286,158 @@ typedef struct dhd_if { bool attached; /* Delayed attachment when unset */ bool txflowcontrol; /* Per interface flow control indicator */ char name[IFNAMSIZ+1]; /* linux interface name */ + uint8 bssidx; /* bsscfg index for the interface */ } dhd_if_t; +#ifdef WLMEDIA_HTSF +typedef struct { + uint32 low; + uint32 high; +} tsf_t; + +typedef struct { + uint32 last_cycle; + uint32 last_sec; + uint32 last_tsf; + uint32 coef; /* scaling factor */ + uint32 coefdec1; /* first decimal */ + uint32 coefdec2; /* second decimal */ +} htsf_t; + +typedef struct { + uint32 t1; + uint32 t2; + uint32 t3; + uint32 t4; +} tstamp_t; + +static tstamp_t ts[TSMAX]; +static tstamp_t maxdelayts; +static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; + +#endif /* WLMEDIA_HTSF */ + /* Local private structure (extension of pub) */ typedef struct dhd_info { -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) wl_iw_t iw; /* wireless extensions state (must be first) */ -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* defined(CONFIG_WIRELESS_EXT) */ dhd_pub_t pub; - /* OS/stack specifics */ + /* For supporting multiple interfaces */ dhd_if_t *iflist[DHD_MAX_IFS]; struct semaphore proto_sem; +#ifdef PROP_TXSTATUS + spinlock_t wlfc_spinlock; +#endif +#ifdef WLMEDIA_HTSF + htsf_t htsf; +#endif wait_queue_head_t ioctl_resp_wait; struct timer_list timer; bool wd_timer_valid; struct tasklet_struct tasklet; spinlock_t sdlock; spinlock_t txqlock; + spinlock_t dhd_lock; +#ifdef DHDTHREAD /* Thread based operation */ bool threads_only; struct semaphore sdsem; - long watchdog_pid; - struct semaphore watchdog_sem; - struct completion watchdog_exited; - long dpc_pid; - struct semaphore dpc_sem; - struct completion dpc_exited; - - /* Thread to work on multicast and multiple interfaces */ - long sysioc_pid; - struct semaphore sysioc_sem; - struct completion sysioc_exited; + + tsk_ctl_t thr_dpc_ctl; + tsk_ctl_t thr_wdt_ctl; + +#else + bool dhd_tasklet_create; +#endif /* DHDTHREAD */ + tsk_ctl_t thr_sysioc_ctl; + + /* Wakelocks */ +#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + struct wake_lock wl_wifi; /* Wifi wakelock */ + struct wake_lock wl_rxwake; /* Wifi rx wakelock */ +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */ +#endif + spinlock_t wakelock_spinlock; + int wakelock_counter; + int wakelock_timeout_enable; + + int hang_was_sent; + + /* Thread to issue ioctl for multicast */ bool set_multicast; bool set_macaddress; struct ether_addr macvalue; - atomic_t pend_8021x_cnt; wait_queue_head_t ctrl_wait; + atomic_t pend_8021x_cnt; + dhd_attach_states_t dhd_state; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ } dhd_info_t; /* Definitions to provide path to the firmware and nvram -* example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" -*/ + * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" + */ char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 +extern int wl_control_wl_start(struct net_device *dev); +extern int net_os_send_hang_message(struct net_device *dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct semaphore dhd_registration_sem; -#endif +#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); +/* Spawn a thread for system ioctls (set mac, set mcast) */ +uint dhd_sysioc = TRUE; +module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_msg_level, int, 0); -/* Spawn a thread for system ioctls (set mac, set mcast) */ -uint dhd_sysioc = TRUE; -module_param(dhd_sysioc, uint, 0); +/* load firmware and/or nvram values from the filesystem */ +module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); -/* Watchdog frequency */ +/* Watchdog interval */ uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); +#if defined(DHD_DEBUG) +/* Console poll interval */ +uint dhd_console_ms = 250; +module_param(dhd_console_ms, uint, 0); +#endif /* defined(DHD_DEBUG) */ + +/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ +uint dhd_arp_mode = 0xb; +module_param(dhd_arp_mode, uint, 0); + +/* ARP offload enable */ +uint dhd_arp_enable = TRUE; +module_param(dhd_arp_enable, uint, 0); + +/* Global Pkt filter enable control */ +uint dhd_pkt_filter_enable = TRUE; +module_param(dhd_pkt_filter_enable, uint, 0); + +/* Pkt filter init setup */ +uint dhd_pkt_filter_init = 0; +module_param(dhd_pkt_filter_init, uint, 0); +/* Pkt filter mode control */ +uint dhd_master_mode = TRUE; +module_param(dhd_master_mode, uint, 1); + +#ifdef DHDTHREAD /* Watchdog thread priority, -1 to use kernel timer */ int dhd_watchdog_prio = 97; module_param(dhd_watchdog_prio, int, 0); @@ -173,6 +449,20 @@ module_param(dhd_dpc_prio, int, 0); /* DPC thread priority, -1 to use tasklet */ extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); +#endif /* DHDTHREAD */ +/* Control fw roaming */ +#ifdef CONFIG_MACH_MAHIMAHI +uint dhd_roam_disable = 0; +#else +uint dhd_roam_disable = 1; +#endif + +/* Control radio state */ +uint dhd_radio_up = 1; + +/* 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); \ @@ -224,6 +514,11 @@ module_param(dhd_rxbound, uint, 0); extern uint dhd_deferred_tx; module_param(dhd_deferred_tx, uint, 0); +#ifdef BCMDBGFS +extern void dhd_dbg_init(dhd_pub_t *dhdp); +extern void dhd_dbg_remove(void); +#endif /* BCMDBGFS */ + #ifdef SDTEST @@ -234,7 +529,7 @@ module_param(dhd_pktgen, uint, 0); /* Echo packet len (0 => sawtooth, max 2040) */ uint dhd_pktgen_len = 0; module_param(dhd_pktgen_len, uint, 0); -#endif +#endif /* SDTEST */ /* Version string to report */ #ifdef DHD_DEBUG @@ -249,10 +544,22 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR #endif ; +#ifdef WLMEDIA_HTSF +void htsf_update(dhd_info_t *dhd, void *data); +tsf_t prev_tsf, cur_tsf; + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); +static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); +static void dhd_dump_latency(void); +static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); +static void dhd_dump_htsfhisto(histo_t *his, char *s); +#endif /* WLMEDIA_HTSF */ + -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* defined(CONFIG_WIRELESS_EXT) */ static void dhd_dpc(ulong data); /* forward decl */ @@ -267,23 +574,27 @@ static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); #endif /* TOE */ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, - wl_event_msg_t *event_ptr, void **data_ptr); + wl_event_msg_t *event_ptr, void **data_ptr); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1 static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) { - switch (action) - { + int ret = NOTIFY_DONE; + + switch (action) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: dhd_mmc_suspend = TRUE; - return NOTIFY_OK; + ret = NOTIFY_OK; + break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: dhd_mmc_suspend = FALSE; - return NOTIFY_OK; + ret = NOTIFY_OK; + break; } - return 0; + smp_mb(); + return ret; } static struct notifier_block dhd_sleep_pm_notifier = { @@ -293,6 +604,127 @@ static struct notifier_block dhd_sleep_pm_notifier = { extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + /* && defined(DHD_GPL) */ +static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) +{ +#ifdef PKT_FILTER_SUPPORT + DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); + /* 1 - Enable packet filter, only allow unicast packet to send up */ + /* 0 - Disable packet filter */ + if (dhd_pkt_filter_enable) { + int i; + + for (i = 0; i < dhd->pktfilter_count; i++) { + dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); + dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], + value, dhd_master_mode); + } + } +#endif +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) +static int dhd_set_suspend(int value, dhd_pub_t *dhd) +{ + int power_mode = PM_MAX; + /* wl_pkt_filter_enable_t enable_parm; */ + char iovbuf[32]; + int bcn_li_dtim = 3; +#ifdef CONFIG_MACH_MAHIMAHI + uint roamvar = 1; +#endif /* CONFIG_MACH_MAHIMAHI */ + + DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", + __FUNCTION__, value, dhd->in_suspend)); + + if (dhd && dhd->up) { + if (value && dhd->in_suspend) { + + /* Kernel suspended */ + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); + + /* Enable packet filter, only allow unicast packet to send up */ + dhd_set_packet_filter(1, dhd); + + /* If DTIM skip is set up as default, force it to wake + * each third DTIM for better power savings. Note that + * one side effect is a chance to miss BC/MC packet. + */ + bcn_li_dtim = dhd_get_dtim_skip(dhd); + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + +#ifdef CONFIG_MACH_MAHIMAHI + /* Disable firmware roaming during suspend */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, + iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* CONFIG_MACH_MAHIMAHI */ + } else { + + /* Kernel resumed */ + DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); + + /* disable pkt filter */ + dhd_set_packet_filter(0, dhd); + + /* restore pre-suspend setting for dtim_skip */ + bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, + 4, iovbuf, sizeof(iovbuf)); + + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#ifdef CONFIG_MACH_MAHIMAHI + roamvar = dhd_roam_disable; + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, + sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* CONFIG_MACH_MAHIMAHI */ + } + } + + return 0; +} + +static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) +{ + dhd_pub_t *dhdp = &dhd->pub; + + DHD_OS_WAKE_LOCK(dhdp); + /* Set flag when early suspend was called */ + dhdp->in_suspend = val; + if (!dhdp->suspend_disable_flag) + dhd_set_suspend(val, dhdp); + DHD_OS_WAKE_UNLOCK(dhdp); +} + +static void dhd_early_suspend(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 1); +} + +static void dhd_late_resume(struct early_suspend *h) +{ + struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + + if (dhd) + dhd_suspend_resume_helper(dhd, 0); +} +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ /* * Generalized timeout mechanism. Uses spin sleep with exponential back-off until @@ -368,6 +800,18 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net) return DHD_BAD_IF; } +struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx) +{ + struct dhd_info *dhd_info; + + if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) + return NULL; + dhd_info = dhd_pub->info; + if (dhd_info && dhd_info->iflist[ifidx]) + return dhd_info->iflist[ifidx]->net; + return NULL; +} + int dhd_ifname2idx(dhd_info_t *dhd, char *name) { @@ -390,19 +834,50 @@ dhd_ifname2idx(dhd_info_t *dhd, char *name) char * dhd_ifname(dhd_pub_t *dhdp, int ifidx) { - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - ASSERT(dhd && dhd->iflist[ifidx]); - if (dhd && dhd->iflist[ifidx]->net) + ASSERT(dhd); + + if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { + DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); + return "<if_bad>"; + } + + if (dhd->iflist[ifidx] == NULL) { + DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); + return "<if_null>"; + } + + if (dhd->iflist[ifidx]->net) return dhd->iflist[ifidx]->net->name; - return "<no ifname>"; + + return "<if_none>"; +} + +uint8 * +dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) +{ + int i; + dhd_info_t *dhd = (dhd_info_t *)dhdp; + + ASSERT(dhd); + for (i = 0; i < DHD_MAX_IFS; i++) + if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) + return dhd->iflist[i]->mac_addr; + + return NULL; } + static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) { struct net_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + struct netdev_hw_addr *ha; +#else struct dev_mc_list *mclist; +#endif uint32 allmulti, cnt; wl_ioctl_t ioc; @@ -412,8 +887,17 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ASSERT(dhd && dhd->iflist[ifidx]); dev = dhd->iflist[ifidx]->net; - mclist = dev->mc_list; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + cnt = netdev_mc_count(dev); +#else cnt = dev->mc_count; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif /* Determine initial value of allmulti flag */ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; @@ -435,10 +919,26 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) memcpy(bufp, &cnt, sizeof(cnt)); bufp += sizeof(cnt); - for (cnt = 0; mclist && (cnt < dev->mc_count); cnt++, mclist = mclist->next) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_lock_bh(dev); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + netdev_for_each_mc_addr(ha, dev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; + cnt--; + } +#else + for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) { memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); bufp += ETHER_ADDR_LEN; } +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + netif_addr_unlock_bh(dev); +#endif memset(&ioc, 0, sizeof(ioc)); ioc.cmd = WLC_SET_VAR; @@ -446,7 +946,7 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ioc.len = buflen; ioc.set = TRUE; - ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); if (ret < 0) { DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", dhd_ifname(&dhd->pub, ifidx), cnt)); @@ -481,7 +981,7 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ioc.len = buflen; ioc.set = TRUE; - ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); if (ret < 0) { DHD_ERROR(("%s: set allmulti %d failed\n", dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); @@ -500,7 +1000,7 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ioc.len = sizeof(allmulti); ioc.set = TRUE; - ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); if (ret < 0) { DHD_ERROR(("%s: set promisc %d failed\n", dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); @@ -524,7 +1024,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) ioc.len = 32; ioc.set = TRUE; - ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); if (ret < 0) { DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); } else { @@ -534,13 +1034,21 @@ _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; +extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ +#endif + static void dhd_op_if(dhd_if_t *ifp) { - dhd_info_t *dhd; - int ret = 0; + dhd_info_t *dhd; + int ret = 0, err = 0; +#ifdef SOFTAP + unsigned long flags; +#endif - ASSERT(ifp && ifp->info && ifp->idx); + ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ dhd = ifp->info; @@ -548,7 +1056,13 @@ dhd_op_if(dhd_if_t *ifp) switch (ifp->state) { case WLC_E_IF_ADD: + /* + * Delete the existing interface before overwriting it + * in case we missed the WLC_E_IF_DEL event. + */ if (ifp->net != NULL) { + DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n", + __FUNCTION__, ifp->net->name)); netif_stop_queue(ifp->net); unregister_netdev(ifp->net); free_netdev(ifp->net); @@ -559,17 +1073,33 @@ dhd_op_if(dhd_if_t *ifp) ret = -ENOMEM; } if (ret == 0) { - strcpy(ifp->net->name, ifp->name); + strncpy(ifp->net->name, ifp->name, IFNAMSIZ); + ifp->net->name[IFNAMSIZ - 1] = '\0'; 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 */ + flags = dhd_os_spin_lock(&dhd->pub); + + /* 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_ctl.sema); + dhd_os_spin_unlock(&dhd->pub, flags); +#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 */ @@ -582,26 +1112,75 @@ dhd_op_if(dhd_if_t *ifp) } 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 + flags = dhd_os_spin_lock(&dhd->pub); + if (ifp->net == ap_net_dev) + ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ + dhd_os_spin_unlock(&dhd->pub, flags); +#endif /* SOFTAP */ } } static int _dhd_sysioc_thread(void *data) { - dhd_info_t *dhd = (dhd_info_t *)data; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + + int i; +#ifdef SOFTAP + bool in_ap = FALSE; + unsigned long flags; +#endif DAEMONIZE("dhd_sysioc"); - while (down_interruptible(&dhd->sysioc_sem) == 0) { + complete(&tsk->completed); + + while (down_interruptible(&tsk->sema) == 0) { + + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { + DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i)); +#ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); + in_ap = (ap_net_dev != NULL); + dhd_os_spin_unlock(&dhd->pub, flags); +#endif /* SOFTAP */ if (dhd->iflist[i]->state) dhd_op_if(dhd->iflist[i]); +#ifdef SOFTAP + if (dhd->iflist[i] == NULL) { + DHD_TRACE(("\n\n %s: interface %d just been removed," + "!\n\n", __FUNCTION__, i)); + continue; + } + + if (in_ap && dhd->set_macaddress) { + DHD_TRACE(("attempt to set MAC for %s in AP Mode," + "blocked. \n", dhd->iflist[i]->net->name)); + dhd->set_macaddress = FALSE; + continue; + } + + if (in_ap && dhd->set_multicast) { + DHD_TRACE(("attempt to set MULTICAST list for %s" + "in AP Mode, blocked. \n", dhd->iflist[i]->net->name)); + dhd->set_multicast = FALSE; + continue; + } +#endif /* SOFTAP */ if (dhd->set_multicast) { dhd->set_multicast = FALSE; _dhd_set_multicast_list(dhd, i); @@ -612,8 +1191,10 @@ _dhd_sysioc_thread(void *data) } } } + DHD_OS_WAKE_UNLOCK(&dhd->pub); } - complete_and_exit(&dhd->sysioc_exited, 0); + DHD_TRACE(("%s: stopped\n", __FUNCTION__)); + complete_and_exit(&tsk->completed, 0); } static int @@ -629,10 +1210,10 @@ dhd_set_mac_address(struct net_device *dev, void *addr) if (ifidx == DHD_BAD_IF) return -1; - ASSERT(dhd->sysioc_pid >= 0); + ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); dhd->set_macaddress = TRUE; - up(&dhd->sysioc_sem); + up(&dhd->thr_sysioc_ctl.sema); return ret; } @@ -647,26 +1228,53 @@ dhd_set_multicast_list(struct net_device *dev) if (ifidx == DHD_BAD_IF) return; - ASSERT(dhd->sysioc_pid >= 0); + ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); dhd->set_multicast = TRUE; - up(&dhd->sysioc_sem); + up(&dhd->thr_sysioc_ctl.sema); } +#ifdef PROP_TXSTATUS +int +dhd_os_wlfc_block(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + ASSERT(di != NULL); + spin_lock_bh(&di->wlfc_spinlock); + return 1; +} + +int +dhd_os_wlfc_unblock(dhd_pub_t *pub) +{ + dhd_info_t *di = (dhd_info_t *)(pub->info); + ASSERT(di != NULL); + spin_unlock_bh(&di->wlfc_spinlock); + return 1; +} + +const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; +uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] + +#endif /* PROP_TXSTATUS */ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { int ret; dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct ether_header *eh = NULL; /* Reject if down */ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { + /* free the packet here since the caller won't */ + PKTFREE(dhdp->osh, pktbuf, TRUE); return -ENODEV; } /* Update multicast statistic */ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) { uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; + eh = (struct ether_header *)pktdata; if (ETHER_ISMULTI(eh->ether_dhost)) dhdp->tx_multicast++; @@ -675,19 +1283,52 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) } /* Look into the packet and update the packet priority */ - if ((PKTPRIO(pktbuf) == 0)) + if (PKTPRIO(pktbuf) == 0) pktsetprio(pktbuf, FALSE); +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state) { + /* store the interface ID */ + DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); + + /* store destination MAC in the tag as well */ + DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); + + /* decide which FIFO this packet belongs to */ + if (ETHER_ISMULTI(eh->ether_dhost)) + /* one additional queue index (highest AC + 1) is used for bc/mc queue */ + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); + else + DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); + } else +#endif /* PROP_TXSTATUS */ /* If the protocol uses a data header, apply it */ dhd_prot_hdrpush(dhdp, ifidx, pktbuf); /* Use bus module to send data frame */ -#ifdef BCMDBUS - ret = dbus_send_pkt(dhdp->dbus, pktbuf, NULL /* pktinfo */); +#ifdef WLMEDIA_HTSF + dhd_htsf_addtxts(dhdp, pktbuf); +#endif +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode + != WLFC_FCMODE_NONE) { + dhd_os_wlfc_block(dhdp); + ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), + pktbuf); + dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, + dhdp->bus); + if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { + ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; + } + dhd_os_wlfc_unblock(dhdp); + } + else + /* non-proptxstatus way */ + ret = dhd_bus_txdata(dhdp->bus, pktbuf); #else - WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMDBUS */ +#endif /* PROP_TXSTATUS */ + return ret; } @@ -699,29 +1340,49 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) void *pktbuf; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); int ifidx; +#ifdef WLMEDIA_HTSF + uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; +#else + uint8 htsfdlystat_sz = 0; +#endif DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_OS_WAKE_LOCK(&dhd->pub); + /* Reject if down */ if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { - DHD_ERROR(("%s: xmit rejected due to dhd bus down status \n", __FUNCTION__)); + DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", + __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); + netif_stop_queue(net); + /* Send Event when bus down detected during data session */ + if (dhd->pub.busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); + net_os_send_hang_message(net); + } + DHD_OS_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } ifidx = dhd_net2idx(dhd, net); if (ifidx == DHD_BAD_IF) { DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); + netif_stop_queue(net); + DHD_OS_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } /* Make sure there's enough room for any header */ - if (skb_headroom(skb) < dhd->pub.hdrlen) { + + if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { struct sk_buff *skb2; DHD_INFO(("%s: insufficient headroom\n", dhd_ifname(&dhd->pub, ifidx))); dhd->pub.tx_realloc++; - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen); + + skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); + dev_kfree_skb(skb); if ((skb = skb2) == NULL) { DHD_ERROR(("%s: skb_realloc_headroom failed\n", @@ -739,6 +1400,17 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ret = -ENOMEM; goto done; } +#ifdef WLMEDIA_HTSF + if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { + uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); + struct ether_header *eh = (struct ether_header *)pktdata; + + if (!ETHER_ISMULTI(eh->ether_dhost) && + (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { + eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); + } + } +#endif ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); @@ -749,6 +1421,8 @@ done: else dhd->pub.tx_packets++; + DHD_OS_WAKE_UNLOCK(&dhd->pub); + /* Return ok: we always eat the packet */ return 0; } @@ -758,26 +1432,44 @@ dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) { struct net_device *net; dhd_info_t *dhd = dhdp->info; + int i; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); dhdp->txoff = state; - ASSERT(dhd && dhd->iflist[ifidx]); - net = dhd->iflist[ifidx]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); + ASSERT(dhd); + + if (ifidx == ALL_INTERFACES) { + /* Flow control on all active interfaces */ + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhd->iflist[i]) { + net = dhd->iflist[i]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } + } + else { + if (dhd->iflist[ifidx]) { + net = dhd->iflist[ifidx]->net; + if (state == ON) + netif_stop_queue(net); + else + netif_wake_queue(net); + } + } } void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) +dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) { - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; struct sk_buff *skb; uchar *eth; uint len; - void * data, *pnext, *save_pktbuf; + void *data, *pnext, *save_pktbuf; int i; dhd_if_t *ifp; wl_event_msg_t event; @@ -787,10 +1479,35 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) save_pktbuf = pktbuf; for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { + struct ether_header *eh; + struct dot11_llc_snap_header *lsh; pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); + eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); + lsh = (struct dot11_llc_snap_header *)&eh[1]; + + if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && + (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && + bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && + lsh->type == HTON16(BTA_PROT_L2CAP)) { + amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) + ((uint8 *)eh + RFC1042_HDR_LEN); + ACL_data = NULL; + } + +#ifdef PROP_TXSTATUS + if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { + /* WLFC may send header only packet when + there is an urgent message but no packet to + piggy-back on + */ + ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; + PKTFREE(dhdp->osh, pktbuf, TRUE); + continue; + } +#endif skb = PKTTONATIVE(dhdp->osh, pktbuf); @@ -821,13 +1538,16 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) skb->data = eth; skb->len = len; +#ifdef WLMEDIA_HTSF + dhd_htsf_addrxts(dhdp, pktbuf); +#endif /* Strip header, count, deliver upward */ skb_pull(skb, ETH_HLEN); /* Process special event packets and then discard them */ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) dhd_wl_host_event(dhd, &ifidx, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) skb->mac_header, #else skb->mac.raw, @@ -835,11 +1555,16 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) &event, &data); + wl_event_to_host_order(&event); + if (event.event_type == WLC_E_BTA_HCI_EVENT) { + dhd_bta_doevt(dhdp, data, event.datalen); + } + + ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) ifp = dhd->iflist[ifidx]; - /* FIX: fix crash for now; can net be NULL?? */ if (ifp->net) ifp->net->last_rx = jiffies; @@ -866,15 +1591,24 @@ 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 +dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) +{ + /* Linux version has nothing to do */ + return; } void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) { - int ifidx; + uint ifidx; dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); struct ether_header *eh; uint16 type; + uint len; dhd_prot_hdrpull(dhdp, &ifidx, txp); @@ -884,6 +1618,21 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) if (type == ETHER_TYPE_802_1X) atomic_dec(&dhd->pend_8021x_cnt); + /* Crack open the packet and check to see if it is BT HCI ACL data packet. + * If yes generate packet completion event. + */ + len = PKTLEN(dhdp->osh, txp); + + /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ + if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { + struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; + + if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && + ntoh16(lsh->type) == BTA_PROT_L2CAP) { + + dhd_bta_tx_hcidata_complete(dhdp, txp, success); + } + } } static struct net_device_stats * @@ -921,18 +1670,17 @@ dhd_get_stats(struct net_device *net) return &ifp->stats; } +#ifdef DHDTHREAD 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"); - + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; /* This thread doesn't need any user-level access, * so get rid of all our resources */ #ifdef DHD_SCHED - if (dhd_watchdog_prio > 0) - { + if (dhd_watchdog_prio > 0) { struct sched_param param; param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? dhd_watchdog_prio:(MAX_RT_PRIO-1); @@ -943,38 +1691,55 @@ dhd_watchdog_thread(void *data) DAEMONIZE("dhd_watchdog"); /* Run until signal received */ - while (1) { - if (down_interruptible (&dhd->watchdog_sem) == 0) { - WAKE_LOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); - - /* Count the tick for reference */ - dhd->pub.tickcnt++; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) { - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms*HZ/1000); + complete(&tsk->completed); + + while (1) + if (down_interruptible (&tsk->sema) == 0) { + + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; } - } - else + + if (dhd->pub.dongle_reset == FALSE) { + DHD_TIMER(("%s:\n", __FUNCTION__)); + + DHD_OS_WAKE_LOCK(&dhd->pub); + + /* Call the bus module watchdog */ + dhd_bus_watchdog(&dhd->pub); + + /* Count the tick for reference */ + dhd->pub.tickcnt++; + /* Reschedule the watchdog */ + 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); + complete_and_exit(&tsk->completed, 0); } +#endif /* DHDTHREAD */ -static void -dhd_watchdog(ulong data) +static void dhd_watchdog(ulong data) { dhd_info_t *dhd = (dhd_info_t *)data; - if (dhd->watchdog_pid >= 0) { - up(&dhd->watchdog_sem); + if (dhd->pub.dongle_reset) { + return; + } + + DHD_OS_WAKE_LOCK(&dhd->pub); +#ifdef DHDTHREAD + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + up(&dhd->thr_wdt_ctl.sema); return; } +#endif /* DHDTHREAD */ /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -983,16 +1748,18 @@ dhd_watchdog(ulong data) dhd->pub.tickcnt++; /* Reschedule the watchdog */ - dhd->timer.expires = jiffies + dhd_watchdog_ms*HZ/1000; - add_timer(&dhd->timer); + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + DHD_OS_WAKE_UNLOCK(&dhd->pub); } +#ifdef DHDTHREAD static int dhd_dpc_thread(void *data) { - dhd_info_t *dhd = (dhd_info_t *)data; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - 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 */ @@ -1006,55 +1773,77 @@ dhd_dpc_thread(void *data) #endif /* DHD_SCHED */ DAEMONIZE("dhd_dpc"); + /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ + + /* signal: thread has started */ + complete(&tsk->completed); /* Run until signal received */ while (1) { - if (down_interruptible(&dhd->dpc_sem) == 0) { + if (down_interruptible(&tsk->sema) == 0) { + + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) { + break; + } + /* 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); + up(&tsk->sema); + DHD_OS_WAKE_LOCK_TIMEOUT(&dhd->pub); + } + 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); + complete_and_exit(&tsk->completed, 0); } +#endif /* DHDTHREAD */ static void dhd_dpc(ulong data) { dhd_info_t *dhd; - dhd = (dhd_info_t*)data; + dhd = (dhd_info_t *)data; + /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] + * down below , wake lock is set, + * the tasklet is initialized in dhd_attach() + */ /* Call bus dpc unless it indicated down (then clean stop) */ if (dhd->pub.busstate != DHD_BUS_DOWN) { if (dhd_bus_dpc(dhd->pub.bus)) tasklet_schedule(&dhd->tasklet); + else + DHD_OS_WAKE_UNLOCK(&dhd->pub); } else { dhd_bus_stop(dhd->pub.bus, TRUE); + DHD_OS_WAKE_UNLOCK(&dhd->pub); } } void dhd_sched_dpc(dhd_pub_t *dhdp) { - dhd_info_t *dhd = (dhd_info_t*)(dhdp->info); + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - if (dhd->dpc_pid >= 0) { - up(&dhd->dpc_sem); + DHD_OS_WAKE_LOCK(dhdp); +#ifdef DHDTHREAD + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + up(&dhd->thr_dpc_ctl.sema); return; } +#endif /* DHDTHREAD */ tasklet_schedule(&dhd->tasklet); } @@ -1076,7 +1865,7 @@ dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) ioc.set = FALSE; strcpy(buf, "toe_ol"); - if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { /* Check for older dongle image that doesn't support toe_ol */ if (ret == -EIO) { DHD_ERROR(("%s: toe not supported by device\n", @@ -1112,7 +1901,7 @@ dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) strcpy(buf, "toe_ol"); memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); - if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); return ret; @@ -1125,7 +1914,7 @@ dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) strcpy(buf, "toe"); memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); - if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); return ret; } @@ -1135,8 +1924,8 @@ dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) #endif /* TOE */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void dhd_ethtool_get_drvinfo(struct net_device *net, - struct ethtool_drvinfo *info) +static void +dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); @@ -1271,28 +2060,40 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) void *buf = NULL; uint driver = 0; int ifidx; - bool is_set_key_cmd; + int ret; + + DHD_OS_WAKE_LOCK(&dhd->pub); ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - if (ifidx == DHD_BAD_IF) + + if (ifidx == DHD_BAD_IF) { + DHD_OS_WAKE_UNLOCK(&dhd->pub); return -1; + } -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) /* linux wireless extensions */ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { /* may recurse, do NOT lock */ - return wl_iw_ioctl(net, ifr, cmd); + ret = wl_iw_ioctl(net, ifr, cmd); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; } -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* defined(CONFIG_WIRELESS_EXT) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) - return (dhd_ethtool(dhd, (void*)ifr->ifr_data)); + if (cmd == SIOCETHTOOL) { + ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - if (cmd != SIOCDEVPRIVATE) + if (cmd != SIOCDEVPRIVATE) { + DHD_OS_WAKE_UNLOCK(&dhd->pub); return -EOPNOTSUPP; + } memset(&ioc, 0, sizeof(ioc)); @@ -1343,9 +2144,8 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) goto done; } - /* send to dongle (must be up, and wl) */ - if (!dhd->pub.up || (dhd->pub.busstate != DHD_BUS_DATA)) { - DHD_TRACE(("DONGLE_DOWN\n")); + /* send to dongle (must be up, and wl). */ + if (dhd->pub.busstate != DHD_BUS_DATA) { bcmerror = BCME_DONGLE_DOWN; goto done; } @@ -1354,25 +2154,81 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) bcmerror = BCME_DONGLE_DOWN; goto done; } - /* Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to - * prevent M4 encryption. - */ - is_set_key_cmd = ((ioc.cmd == WLC_SET_KEY) || - ((ioc.cmd == WLC_SET_VAR) && - !(strncmp("wsec_key", ioc.buf, 9))) || - ((ioc.cmd == WLC_SET_VAR) && - !(strncmp("bsscfg:wsec_key", ioc.buf, 15)))); - if (is_set_key_cmd) { + + /* + * Flush the TX queue if required for proper message serialization: + * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to + * prevent M4 encryption and + * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to + * prevent disassoc frame being sent before WPS-DONE frame. + */ + if (ioc.cmd == WLC_SET_KEY || + (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && + strncmp("wsec_key", ioc.buf, 9) == 0) || + (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && + strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || + ioc.cmd == WLC_DISASSOC) dhd_wait_pend8021x(net); + +#ifdef WLMEDIA_HTSF + if (ioc.buf) { + /* short cut wl ioctl calls here */ + if (strcmp("htsf", ioc.buf) == 0) { + dhd_ioctl_htsf_get(dhd, 0); + return BCME_OK; + } + + if (strcmp("htsflate", ioc.buf) == 0) { + if (ioc.set) { + memset(ts, 0, sizeof(tstamp_t)*TSMAX); + memset(&maxdelayts, 0, sizeof(tstamp_t)); + maxdelay = 0; + tspktcnt = 0; + maxdelaypktno = 0; + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + } else { + dhd_dump_latency(); + } + return BCME_OK; + } + if (strcmp("htsfclear", ioc.buf) == 0) { + memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); + memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); + htsf_seqnum = 0; + return BCME_OK; + } + if (strcmp("htsfhis", ioc.buf) == 0) { + dhd_dump_htsfhisto(&vi_d1, "H to D"); + dhd_dump_htsfhisto(&vi_d2, "D to D"); + dhd_dump_htsfhisto(&vi_d3, "D to H"); + dhd_dump_htsfhisto(&vi_d4, "H to H"); + return BCME_OK; + } + if (strcmp("tsport", ioc.buf) == 0) { + if (ioc.set) { + memcpy(&tsport, ioc.buf + 7, 4); + } else { + DHD_ERROR(("current timestamp port: %d \n", tsport)); + } + return BCME_OK; + } } - WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_IOCTL, "dhd_ioctl_entry"); - WAKE_LOCK(&dhd->pub, WAKE_LOCK_IOCTL); +#endif /* WLMEDIA_HTSF */ - bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + bcmerror = dhd_wl_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 == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && + (!dhd->pub.dongle_reset))) { + DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); + net_os_send_hang_message(net); + } + if (!bcmerror && buf && ioc.buf) { if (copy_to_user(ioc.buf, buf, buflen)) bcmerror = -EFAULT; @@ -1381,27 +2237,33 @@ done: if (buf) MFREE(dhd->pub.osh, buf, buflen); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return OSL_ERROR(bcmerror); } static int dhd_stop(struct net_device *net) { -#if !defined(IGNORE_ETH0_DOWN) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - +#ifdef WL_CFG80211 + wl_cfg80211_down(); +#endif if (dhd->pub.up == 0) { return 0; } +#ifdef PROP_TXSTATUS + dhd_wlfc_cleanup(&dhd->pub); +#endif /* Set state and stop OS transmissions */ dhd->pub.up = 0; netif_stop_queue(net); -#else - DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation ...\n", __FUNCTION__)); -#endif /* !defined(IGNORE_ETH0_DOWN) */ + + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); OLD_MOD_DEC_USE_COUNT; return 0; @@ -1411,15 +2273,29 @@ static int dhd_open(struct net_device *net) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + #ifdef TOE uint32 toe_ol; #endif int ifidx; + int32 ret = 0; + + /* Force start if ifconfig_up gets called before START command */ + wl_control_wl_start(net); ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - ASSERT(ifidx == 0); + if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) { + DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); + return -1; + } + + + if (ifidx == 0) { /* do it only for primary eth0 */ + + + atomic_set(&dhd->pend_8021x_cnt, 0); memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); @@ -1431,13 +2307,23 @@ dhd_open(struct net_device *net) else dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; #endif - + } /* Allow transmit calls */ netif_start_queue(net); dhd->pub.up = 1; +#ifdef WL_CFG80211 + if (unlikely(wl_cfg80211_up())) { + DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); + return -1; + } +#endif /* WL_CFG80211 */ + +#ifdef BCMDBGFS + dhd_dbg_init(&dhd->pub); +#endif OLD_MOD_INC_USE_COUNT; - return 0; + return ret; } osl_t * @@ -1453,15 +2339,14 @@ dhd_osl_detach(osl_t *osh) DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); } osl_detach(osh); - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 up(&dhd_registration_sem); -#endif - +#endif } int -dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr) +dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, + uint8 *mac_addr, uint32 flags, uint8 bssidx) { dhd_if_t *ifp; @@ -1470,10 +2355,17 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr ASSERT(dhd && (ifidx < DHD_MAX_IFS)); ifp = dhd->iflist[ifidx]; - if (!ifp && !(ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t)))) { - DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); - return -ENOMEM; - } + if (ifp != NULL) { + if (ifp->net != NULL) { + netif_stop_queue(ifp->net); + unregister_netdev(ifp->net); + free_netdev(ifp->net); + } + } else + if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { + DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); + return -ENOMEM; + } memset(ifp, 0, sizeof(dhd_if_t)); ifp->info = dhd; @@ -1486,8 +2378,8 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr if (handle == NULL) { ifp->state = WLC_E_IF_ADD; ifp->idx = ifidx; - ASSERT(dhd->sysioc_pid >= 0); - up(&dhd->sysioc_sem); + ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + up(&dhd->thr_sysioc_ctl.sema); } else ifp->net = (struct net_device *)handle; @@ -1510,18 +2402,20 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) ifp->state = WLC_E_IF_DEL; ifp->idx = ifidx; - ASSERT(dhd->sysioc_pid >= 0); - up(&dhd->sysioc_sem); + ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + up(&dhd->thr_sysioc_ctl.sema); } dhd_pub_t * dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) { dhd_info_t *dhd = NULL; - struct net_device *net; + struct net_device *net = NULL; + dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* updates firmware nvram path if it was provided as module paramters */ + + /* updates firmware nvram path if it was provided as module parameters */ if ((firmware_path != NULL) && (firmware_path[0] != '\0')) strcpy(fw_path, firmware_path); if ((nvram_path != NULL) && (nvram_path[0] != '\0')) @@ -1532,28 +2426,65 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); goto fail; } + dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; /* Allocate primary dhd_info */ if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); goto fail; } - memset(dhd, 0, sizeof(dhd_info_t)); +#ifdef DHDTHREAD + dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; + dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; +#else + dhd->dhd_tasklet_create = FALSE; +#endif /* DHDTHREAD */ + dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID; + dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; + /* * Save the dhd_info into the priv */ - memcpy(netdev_priv(net), &dhd, sizeof(dhd)); - + memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd)); dhd->pub.osh = osh; - if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL) == DHD_BAD_IF) + /* Link to info module */ + dhd->pub.info = dhd; + /* Link to bus module */ + dhd->pub.bus = bus; + dhd->pub.hdrlen = bus_hdrlen; + + /* 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; + dhd_state |= DHD_ATTACH_STATE_ADD_IF; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + + sema_init(&dhd->proto_sem, 1); + +#ifdef PROP_TXSTATUS + spin_lock_init(&dhd->wlfc_spinlock); + dhd->pub.wlfc_enabled = TRUE; +#endif /* PROP_TXSTATUS */ - init_MUTEX(&dhd->proto_sem); /* Initialize other structure content */ init_waitqueue_head(&dhd->ioctl_resp_wait); init_waitqueue_head(&dhd->ctrl_wait); @@ -1562,34 +2493,48 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); - /* Link to info module */ - dhd->pub.info = dhd; - - /* Link to bus module */ - dhd->pub.bus = bus; - dhd->pub.hdrlen = bus_hdrlen; + /* Initialize Wakelock stuff */ + spin_lock_init(&dhd->wakelock_spinlock); + dhd->wakelock_counter = 0; + dhd->wakelock_timeout_enable = 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 + dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; /* Attach and link in the protocol */ if (dhd_prot_attach(&dhd->pub) != 0) { DHD_ERROR(("dhd_prot_attach failed\n")); goto fail; } + dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) /* Attach and link in the iw */ if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { DHD_ERROR(("wl_iw_attach failed\n")); goto fail; } -#endif + dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; +#endif /* defined(CONFIG_WIRELESS_EXT) */ +#ifdef WL_CFG80211 + /* Attach and link in the cfg80211 */ + if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { + DHD_ERROR(("wl_cfg80211_attach failed\n")); + goto fail; + } + dhd_state |= DHD_ATTACH_STATE_CFG80211; +#endif /* Set up the watchdog timer */ init_timer(&dhd->timer); dhd->timer.data = (ulong)dhd; dhd->timer.function = dhd_watchdog; +#ifdef DHDTHREAD /* Initialize thread based operation and lock */ - init_MUTEX(&dhd->sdsem); + sema_init(&dhd->sdsem, 1); if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { dhd->threads_only = TRUE; } @@ -1599,101 +2544,120 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) if (dhd_dpc_prio >= 0) { /* Initialize watchdog thread */ - sema_init(&dhd->watchdog_sem, 0); - init_completion(&dhd->watchdog_exited); - dhd->watchdog_pid = kernel_thread(dhd_watchdog_thread, dhd, 0); + PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); } else { - dhd->watchdog_pid = -1; + dhd->thr_wdt_ctl.thr_pid = -1; } /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { /* Initialize DPC thread */ - sema_init(&dhd->dpc_sem, 0); - init_completion(&dhd->dpc_exited); - dhd->dpc_pid = kernel_thread(dhd_dpc_thread, dhd, 0); + PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); } else { + /* use tasklet for dpc */ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->dpc_pid = -1; + dhd->thr_dpc_ctl.thr_pid = -1; } +#else + /* Set up the bottom half handler */ + tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); + dhd->dhd_tasklet_create = TRUE; +#endif /* DHDTHREAD */ if (dhd_sysioc) { - sema_init(&dhd->sysioc_sem, 0); - init_completion(&dhd->sysioc_exited); - dhd->sysioc_pid = kernel_thread(_dhd_sysioc_thread, dhd, 0); + PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); } else { - dhd->sysioc_pid = -1; + dhd->thr_sysioc_ctl.thr_pid = -1; } + dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; /* * Save the dhd_info into the priv */ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) + g_bus = bus; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) && 1 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; + dhd->early_suspend.suspend = dhd_early_suspend; + dhd->early_suspend.resume = dhd_late_resume; + register_early_suspend(&dhd->early_suspend); + dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; +#endif + dhd_state |= DHD_ATTACH_STATE_DONE; + dhd->dhd_state = dhd_state; return &dhd->pub; fail: - if (net) - free_netdev(net); - if (dhd) + if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) { + if (net) free_netdev(net); + } else { + DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", + __FUNCTION__, dhd_state, &dhd->pub)); + dhd->dhd_state = dhd_state; dhd_detach(&dhd->pub); + dhd_free(&dhd->pub); + } return NULL; } - int dhd_bus_start(dhd_pub_t *dhdp) { int ret = -1; dhd_info_t *dhd = (dhd_info_t*)dhdp->info; +#ifdef EMBEDDED_PLATFORM + char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ +#endif /* EMBEDDED_PLATFORM */ ASSERT(dhd); DHD_TRACE(("%s: \n", __FUNCTION__)); /* 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->pub.busstate == DHD_BUS_DOWN) && + (fw_path != NULL) && (fw_path[0] != '\0') && + (nv_path != NULL) && (nv_path[0] != '\0')) { + /* wake lock moved to dhdsdio_download_firmware */ 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); } + if (dhd->pub.busstate != DHD_BUS_LOAD) + return -ENETDOWN; /* Start the watchdog timer */ dhd->pub.tickcnt = 0; dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); /* Bring up the bus */ +#ifdef DHDTHREAD if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) { +#else + if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { +#endif + DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); return ret; } - - #if defined(OOB_INTR_ONLY) /* Host registration for OOB interrupt */ if (bcmsdh_register_oob_intr(dhdp)) { - del_timer(&dhd->timer); + /* deactivate timer and wait for the handler to finish */ dhd->wd_timer_valid = FALSE; - DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); + del_timer_sync(&dhd->timer); + + DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); return -ENODEV; } @@ -1701,20 +2665,64 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_enable_oob_intr(dhd->pub.bus, TRUE); #endif /* defined(OOB_INTR_ONLY) */ - atomic_set(&dhd->pend_8021x_cnt, 0); - /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { - del_timer(&dhd->timer); + del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); return -ENODEV; } +#ifdef EMBEDDED_PLATFORM + bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); + bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN); + + setbit(dhdp->eventmask, WLC_E_SET_SSID); + setbit(dhdp->eventmask, WLC_E_PRUNE); + setbit(dhdp->eventmask, WLC_E_AUTH); + setbit(dhdp->eventmask, WLC_E_REASSOC); + setbit(dhdp->eventmask, WLC_E_REASSOC_IND); + setbit(dhdp->eventmask, WLC_E_DEAUTH_IND); + setbit(dhdp->eventmask, WLC_E_DISASSOC_IND); + setbit(dhdp->eventmask, WLC_E_DISASSOC); + setbit(dhdp->eventmask, WLC_E_JOIN); + setbit(dhdp->eventmask, WLC_E_ASSOC_IND); + setbit(dhdp->eventmask, WLC_E_PSK_SUP); + setbit(dhdp->eventmask, WLC_E_LINK); + setbit(dhdp->eventmask, WLC_E_NDIS_LINK); + setbit(dhdp->eventmask, WLC_E_MIC_ERROR); + setbit(dhdp->eventmask, WLC_E_PMKID_CACHE); + setbit(dhdp->eventmask, WLC_E_TXFAIL); + setbit(dhdp->eventmask, WLC_E_JOIN_START); + setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE); + setbit(dhdp->eventmask, WLC_E_RELOAD); +#ifdef PNO_SUPPORT + setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND); +#endif /* PNO_SUPPORT */ + +/* enable dongle roaming event */ + setbit(dhdp->eventmask, WLC_E_ROAM); + + + dhdp->pktfilter_count = 1; + /* Setup filter to allow only unicast */ + dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00"; +#endif /* EMBEDDED_PLATFORM */ + +#ifdef READ_MACADDR + dhd_read_macaddr(dhd); +#endif + /* Bus is ready, do any protocol initialization */ if ((ret = dhd_prot_init(&dhd->pub)) < 0) return ret; +#ifdef WRITE_MACADDR + /* it could be used even when WIFI is not Enabled [ON] */ + dhd_write_macaddr(dhd->pub.mac.octet); +#endif + return 0; } @@ -1733,170 +2741,324 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; ioc.buf = buf; ioc.len = len; - ioc.set = set; + ioc.set = TRUE; - ret = dhd_prot_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); + ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); if (!set && ret >= 0) memcpy(cmd_buf, buf, cmd_len); return ret; } +#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, + .ndo_get_stats = dhd_get_stats, + .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, +}; + +static struct net_device_ops dhd_ops_virt = { + .ndo_get_stats = dhd_get_stats, + .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, +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ + +int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) +{ + struct dhd_info *dhd = dhdp->info; + struct net_device *dev = NULL; + + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + ASSERT(dev); + + if (netif_running(dev)) { + DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); + return BCME_NOTDOWN; + } + +#define DHD_MIN_MTU 1500 +#define DHD_MAX_MTU 1752 + + if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { + DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); + return BCME_BADARG; + } + + dev->mtu = new_mtu; + return 0; +} int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - struct net_device *net; + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct net_device *net = NULL; + int err = 0; uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ASSERT(dhd && dhd->iflist[ifidx]); - ASSERT(dhd->iflist[ifidx]->net); - ASSERT(!dhd->iflist[ifidx]->net->open); - /* Ok, link into the network layer... */ net = dhd->iflist[ifidx]->net; + ASSERT(net); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->get_stats = dhd_get_stats; + net->do_ioctl = dhd_ioctl_entry; + net->hard_start_xmit = dhd_start_xmit; + net->set_mac_address = dhd_set_mac_address; + net->set_multicast_list = dhd_set_multicast_list; + net->open = net->stop = NULL; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &dhd_ops_virt; +#endif + + /* Ok, link into the network layer... */ if (ifidx == 0) { /* * device functions for the primary interface only */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) net->open = dhd_open; net->stop = dhd_stop; +#else + net->netdev_ops = &dhd_ops_pri; +#endif } else { - net->open = net->stop = NULL; - /* - * We have to use the primary MAC for virtual interfaces - */ + /* + * We have to use the primary MAC for virtual interfaces + */ memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); + if (ifidx == 1) { + DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__)); + /* ACCESSPOINT INTERFACE CASE */ + temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */ + } } - net->get_stats = dhd_get_stats; - net->do_ioctl = dhd_ioctl_entry; - net->hard_start_xmit = dhd_start_xmit; net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; - net->set_mac_address = dhd_set_mac_address; - net->set_multicast_list = dhd_set_multicast_list; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) net->ethtool_ops = &dhd_ethtool_ops; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) #if WIRELESS_EXT < 19 net->get_wireless_stats = dhd_get_wireless_stats; #endif /* WIRELESS_EXT < 19 */ #if WIRELESS_EXT > 12 - net->wireless_handlers = (struct iw_handler_def *) &wl_iw_handler_def; + net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; #endif /* WIRELESS_EXT > 12 */ -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* defined(CONFIG_WIRELESS_EXT) */ - dhd->pub.rxsz = net->mtu + net->hard_header_len; + dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - if (register_netdev(net) != 0) { - DHD_ERROR(("couldn't register the net device\n")); + if ((err = register_netdev(net)) != 0) { + DHD_ERROR(("couldn't register the net device, err %d\n", err)); goto fail; } - 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]); + 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]); + +#if defined(CONFIG_WIRELESS_EXT) +#ifdef SOFTAP + if (ifidx == 0) + /* Don't call for SOFTAP Interface in SOFTAP MODE */ + wl_iw_iscan_set_scan_broadcast_prep(net, 1); +#else + wl_iw_iscan_set_scan_broadcast_prep(net, 1); +#endif /* SOFTAP */ +#endif /* CONFIG_WIRELESS_EXT */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 - up(&dhd_registration_sem); -#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + up(&dhd_registration_sem); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ return 0; + fail: +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) net->open = NULL; - return BCME_ERROR; +#else + net->netdev_ops = NULL; +#endif + return err; } void dhd_bus_detach(dhd_pub_t *dhdp) { - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_info_t *dhd; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); + if (dhdp) { + dhd = (dhd_info_t *)dhdp->info; + if (dhd) { + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); + /* Stop the bus module */ + dhd_bus_stop(dhd->pub.bus, TRUE); + /* Clear the watchdog timer */ + dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); #if defined(OOB_INTR_ONLY) - bcmsdh_unregister_oob_intr(); + bcmsdh_unregister_oob_intr(); #endif /* defined(OOB_INTR_ONLY) */ - - /* Clear the watchdog timer */ - del_timer(&dhd->timer); - dhd->wd_timer_valid = FALSE; + } + } } -void -dhd_detach(dhd_pub_t *dhdp) + +void dhd_detach(dhd_pub_t *dhdp) { - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_info_t *dhd; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (!dhdp) + return; - if (dhd) { + dhd = (dhd_info_t *)dhdp->info; + if (!dhd) + return; + + DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); + + if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { + /* Give sufficient time for threads to start running in case + * dhd_attach() has failed + */ + osl_delay(1000*100); + } + +#if defined(CONFIG_HAS_EARLYSUSPEND) + if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { + if (dhd->early_suspend.suspend) + unregister_early_suspend(&dhd->early_suspend); + } +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + + +#if defined(CONFIG_WIRELESS_EXT) + if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { + /* Detatch and unlink in the iw */ + wl_iw_detach(); + } +#endif /* defined(CONFIG_WIRELESS_EXT) */ + +#ifdef WL_CFG80211 + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) + wl_cfg80211_detach(); +#endif + + if (&dhd->thr_sysioc_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_sysioc_ctl); + } + + /* delete all interfaces, start with virtual */ + if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { + int i = 1; dhd_if_t *ifp; - int i; for (i = 1; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i]) - dhd_del_if(dhd, i); + if (dhd->iflist[i]) { + dhd->iflist[i]->state = WLC_E_IF_DEL; + dhd->iflist[i]->idx = i; + dhd_op_if(dhd->iflist[i]); + } + /* delete primary interface 0 */ ifp = dhd->iflist[0]; ASSERT(ifp); - if (ifp->net->open) { + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + if (ifp->net->open) +#else + if (ifp->net->netdev_ops == &dhd_ops_pri) +#endif + { dhd_stop(ifp->net); unregister_netdev(ifp->net); - } + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - if (dhd->watchdog_pid >= 0) - { - KILL_PROC(dhd->watchdog_pid, SIGTERM); - wait_for_completion(&dhd->watchdog_exited); + } + } + + if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { +#ifdef DHDTHREAD + if (dhd->thr_wdt_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_wdt_ctl); } - if (dhd->dpc_pid >= 0) - { - KILL_PROC(dhd->dpc_pid, SIGTERM); - wait_for_completion(&dhd->dpc_exited); + if (dhd->thr_dpc_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_dpc_ctl); } else +#endif /* DHDTHREAD */ tasklet_kill(&dhd->tasklet); - - if (dhd->sysioc_pid >= 0) { - KILL_PROC(dhd->sysioc_pid, SIGTERM); - wait_for_completion(&dhd->sysioc_exited); - } - + } + if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { dhd_bus_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) + if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 && defined(CONFIG_PM_SLEEP) unregister_pm_notifier(&dhd_sleep_pm_notifier); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#endif + /* && defined(CONFIG_PM_SLEEP) */ - 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)); +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_destroy(&dhd->wl_wifi); + wake_lock_destroy(&dhd->wl_rxwake); +#endif } } + +void +dhd_free(dhd_pub_t *dhdp) +{ + dhd_info_t *dhd; + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (dhdp) { + dhd = (dhd_info_t *)dhdp->info; + if (dhd) + 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(CONFIG_MACH_MAHIMAHI) && 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) { @@ -1904,6 +3066,7 @@ dhd_module_init(void) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#ifdef DHDTHREAD /* Sanity check on the module parameters */ do { /* Both watchdog and DPC as tasklets are ok */ @@ -1917,52 +3080,79 @@ dhd_module_init(void) DHD_ERROR(("Invalid module parameters.\n")); return -EINVAL; } while (0); +#endif /* DHDTHREAD */ /* Call customer gpio to turn on power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 - sema_init(&dhd_registration_sem, 0); -#endif +#if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) + sema_init(&wifi_control_sem, 0); + + /* Added fail_0, fail_1 to do the right clean-up for failure case */ + error = wifi_add_dev(); + if (error) { + DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); + goto fail_0; + } + + /* Waiting callback after platform_driver_register is done or exit with error */ + if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { + error = -EINVAL; + DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); + goto fail_1; + } +#endif /* #if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + sema_init(&dhd_registration_sem, 0); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ error = dhd_bus_register(); if (!error) printf("\n%s\n", dhd_version); + else { + DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); + goto fail_1; + } -#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(3000)) != 0) - DHD_ERROR(("%s: sdio_register_driver failed \n", __FUNCTION__)); -#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ + 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; + } +#endif return error; -} - -static void __exit -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 +fail_2: dhd_bus_unregister(); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +fail_1: +#if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) + wifi_del_dev(); +fail_0: +#endif /* defined(CONFIG_MACH_MAHIMAHI) && 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; +} module_init(dhd_module_init); module_exit(dhd_module_cleanup); /* - * OS specific functions required to implment DHD driver in OS indepedent way + * OS specific functions required to implement DHD driver in OS independent way */ int -dhd_os_proto_block(dhd_pub_t * pub) +dhd_os_proto_block(dhd_pub_t *pub) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); @@ -1975,7 +3165,7 @@ dhd_os_proto_block(dhd_pub_t * pub) } int -dhd_os_proto_unblock(dhd_pub_t * pub) +dhd_os_proto_unblock(dhd_pub_t *pub) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); @@ -2000,24 +3190,35 @@ dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) } int -dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending) +dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); DECLARE_WAITQUEUE(wait, current); int timeout = dhd_ioctl_timeout_msec; /* Convert timeout in millsecond to jiffies */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + timeout = msecs_to_jiffies(timeout); +#else timeout = timeout * HZ / 1000; +#endif /* Wait until control frame is available */ add_wait_queue(&dhd->ioctl_resp_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - while (!(*condition) && (!signal_pending(current) && timeout)) + /* Memory barrier to support multi-processing + * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c]) + * Can be changed by another processor. + */ + smp_mb(); + while (!(*condition) && (!signal_pending(current) && timeout)) { timeout = schedule_timeout(timeout); + smp_mb(); + } if (signal_pending(current)) - * pending = TRUE; + *pending = TRUE; set_current_state(TASK_RUNNING); remove_wait_queue(&dhd->ioctl_resp_wait, &wait); @@ -2026,9 +3227,9 @@ dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending) } int -dhd_os_ioctl_resp_wake(dhd_pub_t * pub) +dhd_os_ioctl_resp_wake(dhd_pub_t *pub) { - dhd_info_t * dhd = (dhd_info_t *)(pub->info); + dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (waitqueue_active(&dhd->ioctl_resp_wait)) { wake_up_interruptible(&dhd->ioctl_resp_wait); @@ -2041,26 +3242,62 @@ void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *) pub->info; + static uint save_dhd_watchdog_ms = 0; + dhd_info_t *dhd = (dhd_info_t *)pub->info; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + /* don't start the wd until fw is loaded */ + if (pub->busstate == DHD_BUS_DOWN) + return; - /* Stop timer and restart at new value */ - if (dhd->wd_timer_valid == TRUE) { + /* Totally stop the timer */ + if (!wdtick && dhd->wd_timer_valid == TRUE) { +#ifdef DHDTHREAD + del_timer_sync(&dhd->timer); +#else del_timer(&dhd->timer); +#endif /* DHDTHREAD */ dhd->wd_timer_valid = FALSE; + save_dhd_watchdog_ms = wdtick; + return; } + if (wdtick) { dhd_watchdog_ms = (uint)wdtick; - dhd->timer.expires = jiffies + dhd_watchdog_ms*HZ/1000; + if (save_dhd_watchdog_ms != dhd_watchdog_ms) { + + if (dhd->wd_timer_valid == TRUE) + /* Stop timer and restart at new value */ +#ifdef DHDTHREAD + del_timer_sync(&dhd->timer); +#else + del_timer(&dhd->timer); +#endif /* DHDTHREAD */ + + /* 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; + } } void * -dhd_os_open_image(char * filename) +dhd_os_open_image(char *filename) { struct file *fp; + /* wl_cfg80211_request_fw(filename); */ + fp = filp_open(filename, O_RDONLY, 0); /* * 2.6.11 (FC4) supports filp_open() but later revs don't? @@ -2075,11 +3312,13 @@ dhd_os_open_image(char * filename) } int -dhd_os_get_image_block(char * buf, int len, void * image) +dhd_os_get_image_block(char *buf, int len, void *image) { - struct file *fp = (struct file *) image; + struct file *fp = (struct file *)image; int rdlen; + /* wl_cfg80211_read_fw(buf, len); */ + if (!image) return 0; @@ -2091,62 +3330,68 @@ dhd_os_get_image_block(char * buf, int len, void * image) } void -dhd_os_close_image(void * image) +dhd_os_close_image(void *image) { + /* wl_cfg80211_release_fw(); */ + if (image) - filp_close((struct file *) image, NULL); + filp_close((struct file *)image, NULL); } void -dhd_os_sdlock(dhd_pub_t * pub) +dhd_os_sdlock(dhd_pub_t *pub) { - dhd_info_t * dhd; + dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); +#ifdef DHDTHREAD if (dhd->threads_only) down(&dhd->sdsem); else +#endif /* DHDTHREAD */ spin_lock_bh(&dhd->sdlock); } void -dhd_os_sdunlock(dhd_pub_t * pub) +dhd_os_sdunlock(dhd_pub_t *pub) { - dhd_info_t * dhd; + dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); +#ifdef DHDTHREAD if (dhd->threads_only) up(&dhd->sdsem); else +#endif /* DHDTHREAD */ spin_unlock_bh(&dhd->sdlock); } void -dhd_os_sdlock_txq(dhd_pub_t * pub) +dhd_os_sdlock_txq(dhd_pub_t *pub) { - dhd_info_t * dhd; + dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); spin_lock_bh(&dhd->txqlock); } void -dhd_os_sdunlock_txq(dhd_pub_t * pub) +dhd_os_sdunlock_txq(dhd_pub_t *pub) { - dhd_info_t * dhd; + dhd_info_t *dhd; dhd = (dhd_info_t *)(pub->info); spin_unlock_bh(&dhd->txqlock); } void -dhd_os_sdlock_rxq(dhd_pub_t * pub) +dhd_os_sdlock_rxq(dhd_pub_t *pub) { } void -dhd_os_sdunlock_rxq(dhd_pub_t * pub) +dhd_os_sdunlock_rxq(dhd_pub_t *pub) { } @@ -2162,13 +3407,40 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } -#ifdef CONFIG_WIRELESS_EXT +#ifdef DHD_USE_STATIC_BUF +void * dhd_os_prealloc(int section, unsigned long size) +{ +#if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) + void *alloc_ptr = NULL; + if (wifi_control_data && wifi_control_data->mem_prealloc) + { + alloc_ptr = wifi_control_data->mem_prealloc(section, size); + if (alloc_ptr) +{ + DHD_INFO(("success alloc section %d\n", section)); + bzero(alloc_ptr, size); + return alloc_ptr; + } +} + + DHD_ERROR(("can't alloc section %d\n", section)); + return 0; +#else +return MALLOC(0, size); +#endif /* #if defined(CONFIG_MACH_MAHIMAHI) && defined(CONFIG_WIFI_CONTROL_FUNC) */ +} +#endif /* DHD_USE_STATIC_BUF */ +#if defined(CONFIG_WIRELESS_EXT) struct iw_statistics * dhd_get_wireless_stats(struct net_device *dev) { int res = 0; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (!dhd->pub.up) { + return NULL; + } + res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); if (res == 0) @@ -2176,25 +3448,36 @@ dhd_get_wireless_stats(struct net_device *dev) else return NULL; } -#endif /* CONFIG_WIRELESS_EXT */ +#endif /* defined(CONFIG_WIRELESS_EXT) */ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_event_msg_t *event, void **data) { int bcmerror = 0; - ASSERT(dhd != NULL); - bcmerror = wl_host_event(dhd, ifidx, pktdata, event, data); + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data); if (bcmerror != BCME_OK) return (bcmerror); -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) ASSERT(dhd->iflist[*ifidx] != NULL); - wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); -#endif /* CONFIG_WIRELESS_EXT */ + /* + * Wireless ext is on primary interface only + */ + if (dhd->iflist[*ifidx]->net && (event->bsscfgidx == 0)) + wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); + +#endif /* defined(CONFIG_WIRELESS_EXT) */ + +#ifdef WL_CFG80211 + ASSERT(dhd->iflist[*ifidx] != NULL); + ASSERT(dhd->iflist[*ifidx]->net != NULL); + if (dhd->iflist[*ifidx]->net) + wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); +#endif return (bcmerror); } @@ -2203,7 +3486,314 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) { + switch (ntoh32(event->event_type)) { + /* Send up locally generated AMP HCI Events */ + case WLC_E_BTA_HCI_EVENT: { + struct sk_buff *p, *skb; + bcm_event_t *msg; + wl_event_msg_t *p_bcm_event; + char *ptr; + uint32 len; + uint32 pktlen; + dhd_if_t *ifp; + dhd_info_t *dhd; + uchar *eth; + int ifidx; + + len = ntoh32(event->datalen); + pktlen = sizeof(bcm_event_t) + len + 2; + dhd = dhdp->info; + ifidx = dhd_ifname2idx(dhd, event->ifname); + + if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { + ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); + + msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); + + bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); + bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); + ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); + + msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); + + /* BCM Vendor specific header... */ + msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); + msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; + bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); + + /* vendor spec header length + pvt data length (private indication + * hdr + actual message itself) + */ + msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + + BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); + msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); + + PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); + + /* copy wl_event_msg_t into sk_buf */ + + /* pointer to wl_event_msg_t in sk_buf */ + p_bcm_event = &msg->event; + bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); + + /* copy hci event into sk_buf */ + bcopy(data, (p_bcm_event + 1), len); + + msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + + ntoh16(msg->bcm_hdr.length)); + PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); + + ptr = (char *)(msg + 1); + /* Last 2 bytes of the message are 0x00 0x00 to signal that there + * are no ethertypes which are following this + */ + ptr[len+0] = 0x00; + ptr[len+1] = 0x00; + + skb = PKTTONATIVE(dhdp->osh, p); + eth = skb->data; + len = skb->len; + + ifp = dhd->iflist[ifidx]; + if (ifp == NULL) + ifp = dhd->iflist[0]; + + ASSERT(ifp); + skb->dev = ifp->net; + skb->protocol = eth_type_trans(skb, skb->dev); + + skb->data = eth; + skb->len = len; + + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Send the packet */ + if (in_interrupt()) { + netif_rx(skb); + } else { + netif_rx_ni(skb); + } + } + else { + /* Could not allocate a sk_buf */ + DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); + } + break; + } /* case WLC_E_BTA_HCI_EVENT */ + + default: + break; + } +} + +void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) +{ +#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + dhd_os_sdunlock(dhd); + wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); + dhd_os_sdlock(dhd); +#endif + return; +} + +void dhd_wait_event_wakeup(dhd_pub_t *dhd) +{ +#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) + struct dhd_info *dhdinfo = dhd->info; + if (waitqueue_active(&dhdinfo->ctrl_wait)) + wake_up_interruptible(&dhdinfo->ctrl_wait); +#endif + return; +} + +int +dhd_dev_reset(struct net_device *dev, uint8 flag) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + /* 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); + DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); + + return 1; +} + +int net_os_set_suspend_disable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + ret = dhd->pub.suspend_disable_flag; + dhd->pub.suspend_disable_flag = val; + } + return ret; +} + +int net_os_set_suspend(struct net_device *dev, int val) +{ + int ret = 0; +#if defined(CONFIG_HAS_EARLYSUSPEND) + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) { + ret = dhd_set_suspend(val, &dhd->pub); + } +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + return ret; +} + +int net_os_set_dtim_skip(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd) + dhd->pub.dtim_skip = val; + + return 0; +} + +int net_os_set_packet_filter(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + /* Packet filtering is set only if we still in early-suspend and + * we need either to turn it ON or turn it OFF + * We can always turn it OFF in case of early-suspend, but we turn it + * back ON only if suspend_disable_flag was not set + */ + if (dhd && dhd->pub.up) { + if (dhd->pub.in_suspend) { + if (!val || (val && !dhd->pub.suspend_disable_flag)) + dhd_set_packet_filter(val, &dhd->pub); + } + } + return ret; +} + + +void +dhd_dev_init_ioctl(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + dhd_preinit_ioctls(&dhd->pub); +} + +#ifdef PNO_SUPPORT +/* Linux wrapper to call common dhd_pno_clean */ +int +dhd_dev_pno_reset(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_clean(&dhd->pub)); +} + + +/* Linux wrapper to call common dhd_pno_enable */ +int +dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_enable(&dhd->pub, pfn_enabled)); +} + + +/* Linux wrapper to call common dhd_pno_set */ +int +dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, + ushort scan_fr, int pno_repeat, int pno_freq_expo_max) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); +} + +/* Linux wrapper to get pno status */ +int +dhd_dev_get_pno_status(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + return (dhd_pno_get_status(&dhd->pub)); +} + +#endif /* PNO_SUPPORT */ + +int net_os_send_hang_message(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) { + if (!dhd->hang_was_sent) { + dhd->hang_was_sent = 1; + ret = wl_iw_send_priv_event(dev, "HANG"); + } + } + return ret; +} + +void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd && dhd->pub.up) + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); +} + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 +void dhd_os_start_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_lock(&dhd->wl_start_lock); +} + +void dhd_os_start_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + mutex_unlock(&dhd->wl_start_lock); +} + +#endif + +#ifdef SOFTAP +unsigned long dhd_os_spin_lock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags = 0; + + if (dhd) + spin_lock_irqsave(&dhd->dhd_lock, flags); + + return flags; +} + +void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + + if (dhd) + spin_unlock_irqrestore(&dhd->dhd_lock, flags); } +#endif /* SOFTAP */ static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd) @@ -2233,42 +3823,647 @@ dhd_wait_pend8021x(struct net_device *dev) return pend; } -void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) +#ifdef DHD_DEBUG +int +write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) { -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - dhd_os_sdunlock(dhd); - wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); - dhd_os_sdlock(dhd); + int ret = 0; + struct file *fp; + mm_segment_t old_fs; + loff_t pos = 0; + + /* change to KERNEL_DS address limit */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + + /* open file to write */ + fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); + if (!fp) { + printf("%s: open file error\n", __FUNCTION__); + ret = -1; + goto exit; + } + + /* Write buf to file */ + fp->f_op->write(fp, buf, size, &pos); + +exit: + /* free buf before return */ + MFREE(dhd->osh, buf, size); + /* close file before return */ + if (fp) + filp_close(fp, current->files); + /* restore previous address limit */ + set_fs(old_fs); + + return ret; +} +#endif /* DHD_DEBUG */ + +int dhd_os_wake_lock_timeout(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + ret = dhd->wakelock_timeout_enable; +#ifdef CONFIG_HAS_WAKELOCK + if (dhd->wakelock_timeout_enable) + wake_lock_timeout(&dhd->wl_rxwake, HZ); #endif - return; + dhd->wakelock_timeout_enable = 0; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; } -void dhd_wait_event_wakeup(dhd_pub_t *dhd) +int net_os_wake_lock_timeout(struct net_device *dev) { -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up_interruptible(&dhdinfo->ctrl_wait); + 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->wakelock_spinlock, flags); + dhd->wakelock_timeout_enable = 1; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + 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->wakelock_spinlock, flags); +#ifdef CONFIG_HAS_WAKELOCK + if (!dhd->wakelock_counter) + wake_lock(&dhd->wl_wifi); #endif - return; + dhd->wakelock_counter++; + ret = dhd->wakelock_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; } -int -dhd_dev_reset(struct net_device *dev, uint8 flag) + +int net_os_wake_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; - dhd_bus_devreset(&dhd->pub, flag); + if (dhd) + ret = dhd_os_wake_lock(&dhd->pub); + return ret; +} - DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); +int dhd_os_wake_unlock(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; - return 1; + dhd_os_wake_lock_timeout(pub); + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (dhd->wakelock_counter) { + dhd->wakelock_counter--; +#ifdef CONFIG_HAS_WAKELOCK + if (!dhd->wakelock_counter) + wake_unlock(&dhd->wl_wifi); +#endif + ret = dhd->wakelock_counter; + } + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; } -void -dhd_dev_init_ioctl(struct net_device *dev) +int net_os_wake_unlock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; - dhd_preinit_ioctls(&dhd->pub); + if (dhd) + ret = dhd_os_wake_unlock(&dhd->pub); + return ret; +} + + +#ifdef PROP_TXSTATUS +extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, + uint8 iftype, uint8* ea); +extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); + +int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype, + uint8* ea) +{ + if (dhd->pub.wlfc_state == NULL) + return BCME_OK; + + return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); +} + +int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) +{ + if (dhd->pub.wlfc_state == NULL) + return BCME_OK; + + return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); +} + +int dhd_wlfc_event(struct dhd_info *dhd) +{ + return dhd_wlfc_enable(&dhd->pub); +} +#endif /* PROP_TXSTATUS */ + +#ifdef BCMDBGFS + +#include <linux/debugfs.h> + +extern uint32 dhd_readregl(void *bp, uint32 addr); +extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); + +typedef struct dhd_dbgfs { + struct dentry *debugfs_dir; + struct dentry *debugfs_mem; + dhd_pub_t *dhdp; + uint32 size; +} dhd_dbgfs_t; + +dhd_dbgfs_t g_dbgfs; + +static int +dhd_dbg_state_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t +dhd_dbg_state_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + uint32 tmp; + loff_t pos = *ppos; + size_t ret; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ + tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); + + ret = copy_to_user(ubuf, &tmp, 4); + if (ret == count) + return -EFAULT; + + count -= ret; + *ppos = pos + count; + rval = count; + + return rval; +} + + +static ssize_t +dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) +{ + loff_t pos = *ppos; + size_t ret; + uint32 buf; + + if (pos < 0) + return -EINVAL; + if (pos >= g_dbgfs.size || !count) + return 0; + if (count > g_dbgfs.size - pos) + count = g_dbgfs.size - pos; + + ret = copy_from_user(&buf, ubuf, sizeof(uint32)); + if (ret == count) + return -EFAULT; + + /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ + dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); + + return count; +} + + +loff_t +dhd_debugfs_lseek(struct file *file, loff_t off, int whence) +{ + loff_t pos = -1; + + switch (whence) { + case 0: + pos = off; + break; + case 1: + pos = file->f_pos + off; + break; + case 2: + pos = g_dbgfs.size - off; + } + return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); +} + +static const struct file_operations dhd_dbg_state_ops = { + .read = dhd_dbg_state_read, + .write = dhd_debugfs_write, + .open = dhd_dbg_state_open, + .llseek = dhd_debugfs_lseek +}; + +static void dhd_dbg_create(void) +{ + if (g_dbgfs.debugfs_dir) { + g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, + NULL, &dhd_dbg_state_ops); + } +} + +void dhd_dbg_init(dhd_pub_t *dhdp) +{ + int err; + + g_dbgfs.dhdp = dhdp; + g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ + + g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); + if (IS_ERR(g_dbgfs.debugfs_dir)) { + err = PTR_ERR(g_dbgfs.debugfs_dir); + g_dbgfs.debugfs_dir = NULL; + return; + } + + dhd_dbg_create(); + + return; +} + +void dhd_dbg_remove(void) +{ + debugfs_remove(g_dbgfs.debugfs_mem); + debugfs_remove(g_dbgfs.debugfs_dir); + + bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); + +} +#endif /* ifdef BCMDBGFS */ + +#ifdef WLMEDIA_HTSF + +static +void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); + struct sk_buff *skb; + uint32 htsf = 0; + uint16 dport = 0, oldmagic = 0xACAC; + char *p1; + htsfts_t ts; + + /* timestamp packet */ + + p1 = (char*) PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { +/* memcpy(&proto, p1+26, 4); */ + memcpy(&dport, p1+40, 2); +/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ + dport = ntoh16(dport); + } + + /* timestamp only if icmp or udb iperf with port 5555 */ +/* if (proto == 17 && dport == tsport) { */ + if (dport >= tsport && dport <= tsport + 20) { + + skb = (struct sk_buff *) pktbuf; + + htsf = dhd_get_htsf(dhd, 0); + memset(skb->data + 44, 0, 2); /* clear checksum */ + memcpy(skb->data+82, &oldmagic, 2); + memcpy(skb->data+84, &htsf, 4); + + memset(&ts, 0, sizeof(htsfts_t)); + ts.magic = HTSFMAGIC; + ts.prio = PKTPRIO(pktbuf); + ts.seqnum = htsf_seqnum++; + ts.c10 = get_cycles(); + ts.t10 = htsf; + ts.endmagic = HTSFENDMAGIC; + + memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); + } +} + +static void dhd_dump_htsfhisto(histo_t *his, char *s) +{ + int pktcnt = 0, curval = 0, i; + for (i = 0; i < (NUMBIN-2); i++) { + curval += 500; + printf("%d ", his->bin[i]); + pktcnt += his->bin[i]; + } + printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, + his->bin[NUMBIN-1], s); +} + +static +void sorttobin(int value, histo_t *histo) +{ + int i, binval = 0; + + if (value < 0) { + histo->bin[NUMBIN-1]++; + return; + } + if (value > histo->bin[NUMBIN-2]) /* store the max value */ + histo->bin[NUMBIN-2] = value; + + for (i = 0; i < (NUMBIN-2); i++) { + binval += 500; /* 500m s bins */ + if (value <= binval) { + histo->bin[i]++; + return; + } + } + histo->bin[NUMBIN-3]++; +} + +static +void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + struct sk_buff *skb; + char *p1; + uint16 old_magic; + int d1, d2, d3, end2end; + htsfts_t *htsf_ts; + uint32 htsf; + + skb = PKTTONATIVE(dhdp->osh, pktbuf); + p1 = (char*)PKTDATA(dhdp->osh, pktbuf); + + if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { + memcpy(&old_magic, p1+78, 2); + htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); + } + else + return; + + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->tE0 = dhd_get_htsf(dhd, 0); + htsf_ts->cE0 = get_cycles(); + } + + if (old_magic == 0xACAC) { + + tspktcnt++; + htsf = dhd_get_htsf(dhd, 0); + memcpy(skb->data+92, &htsf, sizeof(uint32)); + + memcpy(&ts[tsidx].t1, skb->data+80, 16); + + d1 = ts[tsidx].t2 - ts[tsidx].t1; + d2 = ts[tsidx].t3 - ts[tsidx].t2; + d3 = ts[tsidx].t4 - ts[tsidx].t3; + end2end = ts[tsidx].t4 - ts[tsidx].t1; + + sorttobin(d1, &vi_d1); + sorttobin(d2, &vi_d2); + sorttobin(d3, &vi_d3); + sorttobin(end2end, &vi_d4); + + if (end2end > 0 && end2end > maxdelay) { + maxdelay = end2end; + maxdelaypktno = tspktcnt; + memcpy(&maxdelayts, &ts[tsidx], 16); + } + if (++tsidx >= TSMAX) + tsidx = 0; + } +} + +uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) +{ + uint32 htsf = 0, cur_cycle, delta, delta_us; + uint32 factor, baseval, baseval2; + cycles_t t; + + t = get_cycles(); + cur_cycle = t; + + if (cur_cycle > dhd->htsf.last_cycle) + delta = cur_cycle - dhd->htsf.last_cycle; + else { + delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); + } + + delta = delta >> 4; + + if (dhd->htsf.coef) { + /* times ten to get the first digit */ + factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); + baseval = (delta*10)/factor; + baseval2 = (delta*10)/(factor+1); + delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); + htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; + } + else { + DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); + } + + return htsf; +} + +static void dhd_dump_latency(void) +{ + int i, max = 0; + int d1, d2, d3, d4, d5; + + printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); + for (i = 0; i < TSMAX; i++) { + d1 = ts[i].t2 - ts[i].t1; + d2 = ts[i].t3 - ts[i].t2; + d3 = ts[i].t4 - ts[i].t3; + d4 = ts[i].t4 - ts[i].t1; + d5 = ts[max].t4-ts[max].t1; + if (d4 > d5 && d4 > 0) { + max = i; + } + printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", + ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, + d1, d2, d3, d4, i); + } + + printf("current idx = %d \n", tsidx); + + printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); + printf("%08X %08X %08X %08X \t%d %d %d %d\n", + maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, + maxdelayts.t2 - maxdelayts.t1, + maxdelayts.t3 - maxdelayts.t2, + maxdelayts.t4 - maxdelayts.t3, + maxdelayts.t4 - maxdelayts.t1); +} + + +static int +dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) +{ + wl_ioctl_t ioc; + char buf[32]; + int ret; + uint32 s1, s2; + + struct tsf { + uint32 low; + uint32 high; + } tsf_buf; + + memset(&ioc, 0, sizeof(ioc)); + memset(&tsf_buf, 0, sizeof(tsf_buf)); + + ioc.cmd = WLC_GET_VAR; + ioc.buf = buf; + ioc.len = (uint)sizeof(buf); + ioc.set = FALSE; + + strcpy(buf, "tsf"); + s1 = dhd_get_htsf(dhd, 0); + if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { + if (ret == -EIO) { + DHD_ERROR(("%s: tsf is not supported by device\n", + dhd_ifname(&dhd->pub, ifidx))); + return -EOPNOTSUPP; + } + return ret; + } + s2 = dhd_get_htsf(dhd, 0); + + memcpy(&tsf_buf, buf, sizeof(tsf_buf)); + printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", + tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, + dhd->htsf.coefdec2, s2-tsf_buf.low); + printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); + return 0; } + +void htsf_update(dhd_info_t *dhd, void *data) +{ + static ulong cur_cycle = 0, prev_cycle = 0; + uint32 htsf, tsf_delta = 0; + uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; + ulong b, a; + cycles_t t; + + /* cycles_t in inlcude/mips/timex.h */ + + t = get_cycles(); + + prev_cycle = cur_cycle; + cur_cycle = t; + + if (cur_cycle > prev_cycle) + cyc_delta = cur_cycle - prev_cycle; + else { + b = cur_cycle; + a = prev_cycle; + cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); + } + + if (data == NULL) + printf(" tsf update ata point er is null \n"); + + memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); + memcpy(&cur_tsf, data, sizeof(tsf_t)); + + if (cur_tsf.low == 0) { + DHD_INFO((" ---- 0 TSF, do not update, return\n")); + return; + } + + if (cur_tsf.low > prev_tsf.low) + tsf_delta = (cur_tsf.low - prev_tsf.low); + else { + DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", + cur_tsf.low, prev_tsf.low)); + if (cur_tsf.high > prev_tsf.high) { + tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); + DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); + } + else + return; /* do not update */ + } + + if (tsf_delta) { + hfactor = cyc_delta / tsf_delta; + tmp = (cyc_delta - (hfactor * tsf_delta))*10; + dec1 = tmp/tsf_delta; + dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; + tmp = (tmp - (dec1*tsf_delta))*10; + dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; + + if (dec3 > 4) { + if (dec2 == 9) { + dec2 = 0; + if (dec1 == 9) { + dec1 = 0; + hfactor++; + } + else { + dec1++; + } + } + else + dec2++; + } + } + + if (hfactor) { + htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; + dhd->htsf.coef = hfactor; + dhd->htsf.last_cycle = cur_cycle; + dhd->htsf.last_tsf = cur_tsf.low; + dhd->htsf.coefdec1 = dec1; + dhd->htsf.coefdec2 = dec2; + } + else { + htsf = prev_tsf.low; + } +} + +#endif /* WLMEDIA_HTSF */ diff --git a/src/dhd/sys/dhd_linux_sched.c b/src/dhd/sys/dhd_linux_sched.c index 33b9b4f..72290b5 100644 --- a/src/dhd/sys/dhd_linux_sched.c +++ b/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-2011, 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_linux_sched.c,v 1.1.34.1.20.2 2009/01/16 00:00:25 Exp $ + * $Id: dhd_linux_sched.c,v 1.3 2009-04-10 04:14:49 Exp $ */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/src/dhd/sys/dhd_proto.h b/src/dhd/sys/dhd_proto.h index 475a56f..e0a54ad 100644 --- a/src/dhd/sys/dhd_proto.h +++ b/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-2011, 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_proto.h,v 1.2.82.1.4.1.24.4 2009/06/11 19:20:04 Exp $ + * $Id: dhd_proto.h,v 1.8.10.6 2010-12-22 23:47:24 Exp $ */ #ifndef _dhd_proto_h_ @@ -34,7 +34,7 @@ #include <wlioctl.h> #ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 1000 /* In milli second */ +#define IOCTL_RESP_TIMEOUT 20000 /* In milli second */ #endif /* @@ -61,11 +61,14 @@ extern void dhd_prot_stop(dhd_pub_t *dhdp); extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); /* Remove any protocol-specific data header. */ -extern int dhd_prot_hdrpull(dhd_pub_t *, uint *ifidx, void *rxp); +extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp); /* Use protocol to issue ioctl to dongle */ extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); +/* Handles a protocol control response asynchronously */ +extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); + /* Check for and handle local prot-specific iovar commands */ extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, void *params, int plen, void *arg, int len, bool set); @@ -80,6 +83,11 @@ extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buf extern int dhd_preinit_ioctls(dhd_pub_t *dhd); +#ifdef PROP_TXSTATUS +extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); +extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); +extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); +#endif /* PROP_TXSTATUS */ /******************************** * For version-string expansion * diff --git a/src/dhd/sys/dhd_sdio.c b/src/dhd/sys/dhd_sdio.c index a14b3c8..facf6c0 100644 --- a/src/dhd/sys/dhd_sdio.c +++ b/src/dhd/sys/dhd_sdio.c @@ -1,7 +1,7 @@ /* * DHD Bus Module for SDIO * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.36.4.70 2009/10/12 20:22:39 Exp $ + * $Id: dhd_sdio.c,v 1.274.2.40 2011-02-09 22:42:44 Exp $ */ #include <typedefs.h> @@ -40,6 +40,11 @@ #include <siutils.h> #include <hndpmu.h> #include <hndsoc.h> +#include <bcmsdpcm.h> +#if defined(DHD_DEBUG) +#include <hndrte_armtrap.h> +#include <hndrte_cons.h> +#endif /* defined(DHD_DEBUG) */ #include <sbchipc.h> #include <sbhnddma.h> @@ -60,9 +65,13 @@ #include <dhdioctl.h> #include <sdiovar.h> -#define QLEN 128 /* bulk rx and tx queue lengths */ -#define FCHI ((QLEN) - 10) -#define FCLOW ((FCHI)/2) +#ifndef DHDSDIO_MEM_DUMP_FNAME +#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" +#endif + +#define QLEN 256 /* bulk rx and tx queue lengths */ +#define FCHI (QLEN - 10) +#define FCLOW (FCHI / 2) #define PRIOMASK 7 #define TXRETRIES 2 /* # of retries for tx frames */ @@ -77,10 +86,9 @@ #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ -#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -#define MAX_DATA_BUF (32 * 1024) /* which should be more than - * and to hold biggest glom possible - */ +#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ +#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ +#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN @@ -91,7 +99,7 @@ #endif #ifndef DHD_FIRSTREAD -#define DHD_FIRSTREAD 32 +#define DHD_FIRSTREAD 32 #endif #if !ISPOWEROF2(DHD_FIRSTREAD) #error DHD_FIRSTREAD is not a power of 2! @@ -116,16 +124,16 @@ #define MAX_RX_DATASZ 2048 /* Maximum milliseconds to wait for F2 to come up */ -#define DHD_WAIT_F2RDY 4000 +#define DHD_WAIT_F2RDY 3000 /* Bump up limit on waiting for HT to account for first startup; * if the image is doing a CRC calculation before programming the PMU * for HT availability, it could take a couple hundred ms more, so - * max out at a half second (500000us). + * max out at a 1 second (1000000us). */ -#if (PMU_MAX_TRANSITION_DLY <= 500000) +#if (PMU_MAX_TRANSITION_DLY <= 1000000) #undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 500000 +#define PMU_MAX_TRANSITION_DLY 1000000 #endif /* Value for ChipClockCSR during initial setup */ @@ -135,146 +143,173 @@ /* Flags for SDH calls */ #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) -/* Packet free applicable unconditionally for sdio and sdspi. Contional if +/* Packet free applicable unconditionally for sdio and sdspi. Conditional if * bufpool was present for gspi bus. */ #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ PKTFREE(bus->dhd->osh, pkt, FALSE); DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); +#if defined(OOB_INTR_ONLY) +extern void bcmsdh_set_irq(int flag); +#endif /* defined(OOB_INTR_ONLY) */ +#ifdef PROP_TXSTATUS +extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); +#endif -int gDK8 = FALSE; /* Temp flag for DevKit8000 support */ - /* This will go away soon */ +#ifdef DHD_DEBUG +/* Device console log buffer state */ +typedef struct dhd_console { + uint count; /* Poll interval msec counter */ + uint log_addr; /* Log struct address (fixed) */ + hndrte_log_t log; /* Log struct (host copy) */ + uint bufsize; /* Size of log buffer */ + uint8 *buf; /* Log buffer (host copy) */ + uint last; /* Last buffer read index */ +} dhd_console_t; +#endif /* DHD_DEBUG */ -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); /* Private data for SDIO bus interaction */ typedef struct dhd_bus { - dhd_pub_t *dhd; - - bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ - si_t *sih; /* Handle for SI calls */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ - - sdpcmd_regs_t *regs; /* Registers for SDIO core */ - uint sdpcmrev; /* SDIO core revision */ - uint armrev; /* CPU core revision */ - uint ramrev; /* SOCRAM core revision */ - uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ - - uint32 bus; /* gSPI or SDIO bus */ - uint32 hostintmask; /* Copy of Host Interrupt Mask */ - uint32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ + dhd_pub_t *dhd; + + bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ + si_t *sih; /* Handle for SI calls */ + char *vars; /* Variables (from CIS and/or other) */ + uint varsz; /* Size of variables buffer */ + uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ + + sdpcmd_regs_t *regs; /* Registers for SDIO core */ + uint sdpcmrev; /* SDIO core revision */ + uint armrev; /* CPU core revision */ + uint ramrev; /* SOCRAM core revision */ + uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ + uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ + + uint32 bus; /* gSPI or SDIO bus */ + uint32 hostintmask; /* Copy of Host Interrupt Mask */ + uint32 intstatus; /* Intstatus bits (events) pending */ + bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ + bool fcstate; /* State of dongle flow-control */ + + uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ char *fw_path; /* module_param: path to firmware image */ char *nv_path; /* module_param: path to nvram vars file */ - const char *nvram_params; /* user specified nvram params. */ + const char *nvram_params; /* user specified nvram params. */ - uint blocksize; /* Block size of SDIO transfers */ - uint roundup; /* Max roundup limit */ + uint blocksize; /* Block size of SDIO transfers */ + uint roundup; /* Max roundup limit */ - struct pktq txq; /* Queue length used for flow-control */ - uint8 flowcontrol; /* per prio flow control bitmask */ - uint8 tx_seq; /* Transmit sequence number (next) */ - uint8 tx_max; /* Maximum transmit sequence allowed */ + struct pktq txq; /* Queue length used for flow-control */ + uint8 flowcontrol; /* per prio flow control bitmask */ + uint8 tx_seq; /* Transmit sequence number (next) */ + uint8 tx_max; /* Maximum transmit sequence allowed */ uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; - uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - uint16 nextlen; /* Next Read Len from last header */ - uint8 rx_seq; /* Receive sequence number (expected) */ - bool rxskip; /* Skip receive (awaiting NAK ACK) */ - - void *glomd; /* Packet containing glomming descriptor */ - void *glom; /* Packet chain for glommed superframe */ - uint glomerr; /* Glom packet read errors */ - - uint8 *rxbuf; /* Buffer for receiving control packets */ - uint rxblen; /* Allocated length of rxbuf */ - uint8 *rxctl; /* Aligned pointer into rxbuf */ - uint8 *databuf; /* Buffer for receiving big glom packet */ - uint8 *dataptr; /* Aligned pointer into databuf */ - uint rxlen; /* Length of valid data in buffer */ - - uint8 sdpcm_ver; /* Bus protocol reported by dongle */ - - bool intr; /* Use interrupts */ - bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ - bool intdis; /* Interrupts disabled by isr */ - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ - uint spurious; /* Count of spurious interrupts */ - uint pollrate; /* Ticks between device polls */ - uint polltick; /* Tick counter */ - uint pollcnt; /* Count of active polls */ - - uint regfails; /* Count of R_REG/W_REG failures */ - - uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ - int32 idletime; /* Control for activity timeout */ - uint32 idlecount; /* Activity timeout counter */ - int32 idleclock; /* How to set bus driver when idle */ - uint32 sd_divisor; /* Speed control to bus driver */ - uint32 sd_mode; /* Mode control to bus driver */ - uint32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ - bool use_rxchain; /* If dhd should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ - bool rxflow_mode; /* Is the rx flow control mechanism enable */ + uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ + uint16 nextlen; /* Next Read Len from last header */ + uint8 rx_seq; /* Receive sequence number (expected) */ + bool rxskip; /* Skip receive (awaiting NAK ACK) */ + + void *glomd; /* Packet containing glomming descriptor */ + void *glom; /* Packet chain for glommed superframe */ + uint glomerr; /* Glom packet read errors */ + + uint8 *rxbuf; /* Buffer for receiving control packets */ + uint rxblen; /* Allocated length of rxbuf */ + uint8 *rxctl; /* Aligned pointer into rxbuf */ + uint8 *databuf; /* Buffer for receiving big glom packet */ + uint8 *dataptr; /* Aligned pointer into databuf */ + uint rxlen; /* Length of valid data in buffer */ + + uint8 sdpcm_ver; /* Bus protocol reported by dongle */ + + bool intr; /* Use interrupts */ + bool poll; /* Use polling */ + bool ipend; /* Device interrupt is pending */ + bool intdis; /* Interrupts disabled by isr */ + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + uint spurious; /* Count of spurious interrupts */ + uint pollrate; /* Ticks between device polls */ + uint polltick; /* Tick counter */ + uint pollcnt; /* Count of active polls */ + +#ifdef DHD_DEBUG + dhd_console_t console; /* Console output polling support */ + uint console_addr; /* Console address from shared struct */ +#endif /* DHD_DEBUG */ + + uint regfails; /* Count of R_REG/W_REG failures */ + + uint clkstate; /* State of sd and backplane clock(s) */ + bool activity; /* Activity flag for clock down */ + int32 idletime; /* Control for activity timeout */ + int32 idlecount; /* Activity timeout counter */ + int32 idleclock; /* How to set bus driver when idle */ + int32 sd_divisor; /* Speed control to bus driver */ + int32 sd_mode; /* Mode control to bus driver */ + int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ + bool use_rxchain; /* If dhd should use PKT chains */ + bool sleeping; /* Is SDIO bus sleeping? */ + bool rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ - uint prev_rxlim_hit; /* Is the previous rx limit exceeded (per dpc schedule) */ - bool alp_only; /* Don't use HT clock (ALP only) */ + uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ + bool alp_only; /* Don't use HT clock (ALP only) */ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ bool usebufpool; #ifdef SDTEST /* external loopback */ - bool ext_loop; - uint8 loopid; + bool ext_loop; + uint8 loopid; /* pktgen configuration */ - uint pktgen_freq; /* Ticks between bursts */ - uint pktgen_count; /* Packets to send each burst */ - uint pktgen_print; /* Bursts between count displays */ - uint pktgen_total; /* Stop after this many */ - uint pktgen_minlen; /* Minimum packet data len */ - uint pktgen_maxlen; /* Maximum packet data len */ - uint pktgen_mode; /* Configured mode: tx, rx, or echo */ - uint pktgen_stop; /* Number of tx failures causing stop */ + uint pktgen_freq; /* Ticks between bursts */ + uint pktgen_count; /* Packets to send each burst */ + uint pktgen_print; /* Bursts between count displays */ + uint pktgen_total; /* Stop after this many */ + uint pktgen_minlen; /* Minimum packet data len */ + uint pktgen_maxlen; /* Maximum packet data len */ + uint pktgen_mode; /* Configured mode: tx, rx, or echo */ + uint pktgen_stop; /* Number of tx failures causing stop */ /* active pktgen fields */ - uint pktgen_tick; /* Tick counter for bursts */ - uint pktgen_ptick; /* Burst counter for printing */ - uint pktgen_sent; /* Number of test packets generated */ - uint pktgen_rcvd; /* Number of test packets received */ - uint pktgen_fail; /* Number of failed send attempts */ - uint16 pktgen_len; /* Length of next packet to send */ + uint pktgen_tick; /* Tick counter for bursts */ + uint pktgen_ptick; /* Burst counter for printing */ + uint pktgen_sent; /* Number of test packets generated */ + uint pktgen_rcvd; /* Number of test packets received */ + uint pktgen_fail; /* Number of failed send attempts */ + uint16 pktgen_len; /* Length of next packet to send */ +#define PKTGEN_RCV_IDLE (0) +#define PKTGEN_RCV_ONGOING (1) + uint16 pktgen_rcv_state; /* receive state */ + uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ #endif /* SDTEST */ /* Some additional counters */ - uint tx_sderrs; /* Count of tx attempts with sd errors */ - uint fcqueued; /* Tx packets that got queued */ - uint rxrtx; /* Count of rtx requests (NAK to dongle) */ - uint rx_toolong; /* Receive frames too long to receive */ - uint rxc_errors; /* SDIO errors when reading control frames */ - uint rx_hdrfail; /* SDIO errors on header reads */ - uint rx_badhdr; /* Bad received headers (roosync?) */ - uint rx_badseq; /* Mismatched rx sequence number */ - uint fc_rcvd; /* Number of flow-control events received */ - uint fc_xoff; /* Number which turned on flow-control */ - uint fc_xon; /* Number which turned off flow-control */ - uint rxglomfail; /* Failed deglom attempts */ - uint rxglomframes; /* Number of glom frames (superframes) */ - uint rxglompkts; /* Number of packets from glom frames */ - uint f2rxhdrs; /* Number of header reads */ - uint f2rxdata; /* Number of frame data reads */ - uint f2txdata; /* Number of f2 frame writes */ - uint f1regdata; /* Number of f1 register accesses */ - + uint tx_sderrs; /* Count of tx attempts with sd errors */ + uint fcqueued; /* Tx packets that got queued */ + uint rxrtx; /* Count of rtx requests (NAK to dongle) */ + uint rx_toolong; /* Receive frames too long to receive */ + uint rxc_errors; /* SDIO errors when reading control frames */ + uint rx_hdrfail; /* SDIO errors on header reads */ + uint rx_badhdr; /* Bad received headers (roosync?) */ + uint rx_badseq; /* Mismatched rx sequence number */ + uint fc_rcvd; /* Number of flow-control events received */ + uint fc_xoff; /* Number which turned on flow-control */ + uint fc_xon; /* Number which turned off flow-control */ + uint rxglomfail; /* Failed deglom attempts */ + uint rxglomframes; /* Number of glom frames (superframes) */ + uint rxglompkts; /* Number of packets from glom frames */ + uint f2rxhdrs; /* Number of header reads */ + uint f2rxdata; /* Number of frame data reads */ + uint f2txdata; /* Number of f2 frame writes */ + uint f1regdata; /* Number of f1 register accesses */ + + uint8 *ctrl_frame_buf; + uint32 ctrl_frame_len; + bool ctrl_frame_stat; + uint32 rxint_mode; /* rx interrupt mode */ } dhd_bus_t; /* clkstate */ @@ -293,6 +328,9 @@ static int tx_packets[NUMPRIO]; /* Deferred transmit */ const uint dhd_deferred_tx = 1; +extern uint dhd_watchdog_ms; +extern void dhd_os_wd_timer(void *bus, uint wdtick); + /* Tx/Rx bounds */ uint dhd_txbound; uint dhd_rxbound; @@ -323,21 +361,23 @@ static bool forcealign; #define ALIGNMENT 4 +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); +#endif + #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ - -#define PKTALIGN(osh, p, len, align) \ - do { \ - uint datalign; \ - \ - datalign = (uintptr)PKTDATA((osh), (p)); \ - datalign = ROUNDUP(datalign, (align)) - datalign; \ - ASSERT(datalign < (align)); \ - ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ - if (datalign) \ - PKTPULL((osh), (p), datalign); \ - PKTSETLEN((osh), (p), (len)); \ +#define PKTALIGN(osh, p, len, align) \ + do { \ + uint datalign; \ + datalign = (uintptr)PKTDATA((osh), (p)); \ + datalign = ROUNDUP(datalign, (align)) - datalign; \ + ASSERT(datalign < (align)); \ + ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ + if (datalign) \ + PKTPULL((osh), (p), datalign); \ + PKTSETLEN((osh), (p), (len)); \ } while (0) /* Limit on rounding up frames */ @@ -385,20 +425,50 @@ do { \ } while (0) +/* + * pktavail interrupts from dongle to host can be managed in 3 different ways + * whenever there is a packet available in dongle to transmit to host. + * + * Mode 0: Dongle writes the software host mailbox and host is interrupted. + * Mode 1: (sdiod core rev >= 4) + * Device sets a new bit in the intstatus whenever there is a packet + * available in fifo. Host can't clear this specific status bit until all the + * packets are read from the FIFO. No need to ack dongle intstatus. + * Mode 2: (sdiod core rev >= 4) + * Device sets a bit in the intstatus, and host acks this by writing + * one to this bit. Dongle won't generate anymore packet interrupts + * until host reads all the packets from the dongle and reads a zero to + * figure that there are no more packets. No need to disable host ints. + * Need to ack the intstatus. + */ + +#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ +#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ +#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ + + +#define FRAME_AVAIL_MASK(bus) \ + ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) + #define DHD_BUS SDIO_BUS -#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) +#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) -#define HOSTINTMASK (I_TOHOSTMAIL | I_CHIPACTIVE) +#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) #define GSPI_PR55150_BAILOUT #ifdef SDTEST static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start); +static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count); #endif +#ifdef DHD_DEBUG +static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size); +static int dhdsdio_mem_dump(dhd_bus_t *bus); +static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); +#endif /* DHD_DEBUG */ static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); @@ -409,9 +479,7 @@ static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, void * regsva, uint16 devid); static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh); - -static uint process_nvram_vars(char *varbuf, uint len); +static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation); static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, @@ -421,15 +489,20 @@ static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh); -static int _dhdsdio_download_firmware(struct dhd_bus *bus); +static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); +static int _dhdsdio_download_firmware(dhd_bus_t *bus); -static int dhdsdio_download_code_file(struct dhd_bus *bus, char *image_path); -static int dhdsdio_download_nvram(struct dhd_bus *bus); +static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); +static int dhdsdio_download_nvram(dhd_bus_t *bus); #ifdef BCMEMBEDIMAGE -static int dhdsdio_download_code_array(struct dhd_bus *bus); +static int dhdsdio_download_code_array(dhd_bus_t *bus); #endif +#ifdef WLMEDIA_HTSF +#include <htsf.h> +extern uint32 dhd_get_htsf(void *dhd, int ifidx); +#endif /* WLMEDIA_HTSF */ + static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) { @@ -479,9 +552,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) /* Request HT Avail */ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0)) - clkreq |= SBSDIO_FORCE_ALP; - @@ -506,9 +576,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) { @@ -519,6 +586,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 */ @@ -666,8 +735,7 @@ dhdsdio_sdclk(dhd_bus_t *bus, bool on) return BCME_ERROR; } } - if (!gDK8) - bus->clkstate = CLK_NONE; + bus->clkstate = CLK_NONE; } return BCME_OK; @@ -677,6 +745,7 @@ dhdsdio_sdclk(dhd_bus_t *bus, bool on) static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) { + int ret = BCME_OK; #ifdef DHD_DEBUG uint oldstate = bus->clkstate; #endif /* DHD_DEBUG */ @@ -685,9 +754,11 @@ 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 (target == CLK_AVAIL) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); bus->activity = TRUE; - return BCME_OK; + } + return ret; } switch (target) { @@ -696,39 +767,47 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) if (bus->clkstate == CLK_NONE) dhdsdio_sdclk(bus, TRUE); /* Now request HT Avail on the backplane */ - dhdsdio_htclk(bus, TRUE, pendok); - bus->activity = TRUE; + ret = dhdsdio_htclk(bus, TRUE, pendok); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; + } break; case CLK_SDONLY: /* Remove HT request, or bring up SD clock */ if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); + ret = dhdsdio_sdclk(bus, TRUE); else if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); + ret = dhdsdio_htclk(bus, FALSE, FALSE); else DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", bus->clkstate, target)); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + } break; case CLK_NONE: /* Make sure to remove HT request */ - if (!gDK8) { - if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); - /* Now remove the SD clock */ - dhdsdio_sdclk(bus, FALSE); - } + if (bus->clkstate == CLK_AVAIL) + ret = dhdsdio_htclk(bus, FALSE, FALSE); + /* Now remove the SD clock */ + ret = dhdsdio_sdclk(bus, FALSE); +#ifdef DHD_DEBUG + if (dhd_console_ms == 0) +#endif /* DHD_DEBUG */ + dhd_os_wd_timer(bus->dhd, 0); break; } #ifdef DHD_DEBUG DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); #endif /* DHD_DEBUG */ - return BCME_OK; + return ret; } -int +static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) { bcmsdh_info_t *sdh = bus->sdh; @@ -768,10 +847,8 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); /* Isolate the bus */ - if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - } + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); /* Change state */ bus->sleeping = TRUE; @@ -783,8 +860,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) 0, NULL); /* Force pad isolation off if possible (in case power never toggled) */ - if ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev >= 10)) - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); /* Make sure the controller has the bus up */ @@ -794,6 +870,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) W_SDREG(0, ®s->tosbmailboxdata, retries); if (retries <= retry_limit) W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + if (retries > retry_limit) DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); @@ -817,6 +894,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) { +#if defined(HW_OOB) + bcmsdh_enable_hw_oob_intr(bus->sdh, enable); +#else sdpcmd_regs_t *regs = bus->regs; uint retries = 0; @@ -837,6 +917,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(OOB_INTR_ONLY) */ @@ -861,6 +942,11 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) bcmsdh_info_t *sdh; void *new; int i; +#ifdef WLMEDIA_HTSF + char *p; + htsfts_t *htsf_ts; +#endif + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -874,6 +960,17 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) frame = (uint8*)PKTDATA(osh, pkt); +#ifdef WLMEDIA_HTSF + if (PKTLEN(osh, pkt) >= 100) { + p = PKTDATA(osh, pkt); + htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); + if (htsf_ts->magic == HTSFMAGIC) { + htsf_ts->c20 = get_cycles(); + htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); + } + } +#endif /* WLMEDIA_HTSF */ + /* Add alignment padding, allocate new packet if needed */ if ((pad = ((uintptr)frame % DHD_SDALIGN))) { if (PKTHEADROOM(osh, pkt) < pad) { @@ -918,7 +1015,6 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; #ifdef DHD_DEBUG tx_packets[PKTPRIO(pkt)]++; @@ -957,7 +1053,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) do { ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, pkt, NULL, NULL); + frame, len, pkt, NULL, NULL); bus->f2txdata++; ASSERT(ret != BCME_PENDING); @@ -984,73 +1080,29 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) } } + if (ret == 0) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } } while ((ret < 0) && retrydata && retries++ < TXRETRIES); done: /* restore pkt buffer pointer before calling tx complete routine */ PKTPULL(osh, pkt, SDPCM_HDRLEN + pad); - dhd_os_sdunlock(bus->dhd); +#ifdef PROP_TXSTATUS + if (bus->dhd->wlfc_state) { + dhd_os_sdunlock(bus->dhd); + dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0); + dhd_os_sdlock(bus->dhd); + } else { +#endif /* PROP_TXSTATUS */ dhd_txcomplete(bus->dhd, pkt, ret != 0); - dhd_os_sdlock(bus->dhd); - if (free_pkt) PKTFREE(osh, pkt, TRUE); - return ret; -} - -static bool -dhd_prec_enq(struct dhd_bus *bus, struct pktq *q, void *pkt, int prec) -{ - void *p; - int eprec = -1; /* precedence to evict from */ - bool discard_oldest; - - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(q, prec) && !pktq_full(q)) { - pktq_penq(q, prec, pkt); - return TRUE; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = pktq_peek_tail(q, &eprec); - ASSERT(p); - if (eprec > prec) - return FALSE; +#ifdef PROP_TXSTATUS } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(q, eprec)); - discard_oldest = AC_BITMAP_TST(bus->dhd->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return FALSE; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - if (p == NULL) { - DHD_ERROR(("%s: pktq_penq() failed, oldest %d.", - __FUNCTION__, discard_oldest)); - ASSERT(p); - } - - PKTFREE(bus->dhd->osh, p, TRUE); - } - - /* Enqueue */ - p = pktq_penq(q, prec, pkt); - if (p == NULL) { - DHD_ERROR(("%s: pktq_penq() failed.", __FUNCTION__)); - ASSERT(p); - } - - return TRUE; +#endif + return ret; } int @@ -1084,19 +1136,46 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); - +#ifndef DHDTHREAD + /* Lock: we're about to use shared data/code (and SDIO) */ + dhd_os_sdlock(bus->dhd); +#endif /* DHDTHREAD */ /* Check for existing queue, current flow-control, pending event, or pending clock */ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || - (bus->clkstate == CLK_PENDING)) { + (bus->clkstate != CLK_AVAIL)) { + DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, + pktq_len(&bus->txq))); bus->fcqueued++; /* Priority based enq */ dhd_os_sdlock_txq(bus->dhd); - if (dhd_prec_enq(bus, &bus->txq, pkt, prec) == FALSE) { + if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { PKTPULL(osh, pkt, SDPCM_HDRLEN); +#ifndef DHDTHREAD + /* Need to also release txqlock before releasing sdlock. + * This thread still has txqlock and releases sdlock. + * Deadlock happens when dpc() grabs sdlock first then + * attempts to grab txqlock. + */ + dhd_os_sdunlock_txq(bus->dhd); + dhd_os_sdunlock(bus->dhd); +#endif +#ifdef PROP_TXSTATUS + if (bus->dhd->wlfc_state) + dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE); + else +#endif dhd_txcomplete(bus->dhd, pkt, FALSE); +#ifndef DHDTHREAD + dhd_os_sdlock(bus->dhd); + dhd_os_sdlock_txq(bus->dhd); +#endif +#ifdef PROP_TXSTATUS + /* let the caller decide whether to free the packet */ + if (!bus->dhd->wlfc_state) +#endif PKTFREE(osh, pkt, TRUE); ret = BCME_NORESOURCE; } @@ -1105,7 +1184,7 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) dhd_os_sdunlock_txq(bus->dhd); if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) - dhd_txflowcontrol(bus->dhd, 0, ON); + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); #ifdef DHD_DEBUG if (pktq_plen(&bus->txq, prec) > qcount[prec]) @@ -1117,13 +1196,15 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) dhd_sched_dpc(bus->dhd); } } else { +#ifdef DHDTHREAD /* Lock: we're about to use shared data/code (and SDIO) */ dhd_os_sdlock(bus->dhd); +#endif /* DHDTHREAD */ /* Otherwise, send it now */ BUS_WAKE(bus); + /* Make sure back plane ht clk is on, no pending allowed */ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - #ifndef SDTEST ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); #else @@ -1140,9 +1221,14 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) dhdsdio_clkctl(bus, CLK_NONE, TRUE); } +#ifdef DHDTHREAD dhd_os_sdunlock(bus->dhd); +#endif /* DHDTHREAD */ } +#ifndef DHDTHREAD + dhd_os_sdunlock(bus->dhd); +#endif /* DHDTHREAD */ return ret; } @@ -1202,7 +1288,7 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) /* Deflow-control stack if needed */ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) - dhd_txflowcontrol(dhd, 0, OFF); + dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); return cnt; } @@ -1273,47 +1359,73 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("Tx Frame", frame, len); - } else if (DHD_HDRS_ON()) { - prhex("TxHdr", frame, MIN(len, 16)); + if (!DATAOK(bus)) { + DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", + __FUNCTION__, bus->tx_max, bus->tx_seq)); + bus->ctrl_frame_stat = TRUE; + /* Send from dpc */ + bus->ctrl_frame_buf = frame; + bus->ctrl_frame_len = len; + + dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); + + if (bus->ctrl_frame_stat == FALSE) { + DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); + ret = 0; + } else { + DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__)); + ret = -1; + bus->ctrl_frame_stat = FALSE; + goto done; + } } + + if (ret == -1) { +#ifdef DHD_DEBUG + if (DHD_BYTES_ON() && DHD_CTL_ON()) { + prhex("Tx Frame", frame, len); + } else if (DHD_HDRS_ON()) { + prhex("TxHdr", frame, MIN(len, 16)); + } #endif - do { - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, NULL, NULL, NULL); - ASSERT(ret != BCME_PENDING); + do { + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + frame, len, NULL, NULL, NULL); + ASSERT(ret != BCME_PENDING); - if (ret < 0) { + if (ret < 0) { /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - - bcmsdh_abort(sdh, SDIO_FUNC_2); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; + DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + + bcmsdh_abort(sdh, SDIO_FUNC_2); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + uint8 hi, lo; + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } - for (i = 0; i < 3; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; } + if (ret == 0) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + } while ((ret < 0) && retries++ < TXRETRIES); + } - } - } while ((ret < 0) && retries++ < TXRETRIES); - +done: if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { bus->activity = FALSE; dhdsdio_clkctl(bus, CLK_NONE, TRUE); @@ -1355,11 +1467,21 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); +#ifdef DHD_DEBUG + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); +#endif /* DHD_DEBUG */ } else if (pending == TRUE) { - DHD_CTL(("%s: cancelled\n", __FUNCTION__)); + DHD_CTL(("%s: canceled\n", __FUNCTION__)); return -ERESTARTSYS; } else { DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); +#ifdef DHD_DEBUG + dhd_os_sdlock(bus->dhd); + dhdsdio_checkdied(bus, NULL, 0); + dhd_os_sdunlock(bus->dhd); +#endif /* DHD_DEBUG */ } if (rxlen) @@ -1367,7 +1489,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) else bus->dhd->rx_ctlerrs++; - return rxlen ? rxlen : -ETIMEDOUT; + return rxlen ? (int)rxlen : -ETIMEDOUT; } /* IOVar table */ @@ -1379,7 +1501,12 @@ enum { IOV_SDCIS, IOV_MEMBYTES, IOV_MEMSIZE, +#ifdef DHD_DEBUG + IOV_CHECKDIED, + IOV_SERIALCONS, +#endif IOV_DOWNLOAD, + IOV_SOCRAM_STATE, IOV_FORCEEVEN, IOV_SDIOD_DRIVE, IOV_READAHEAD, @@ -1400,7 +1527,11 @@ enum { IOV_IDLECLOCK, IOV_SD1IDLE, IOV_SLEEP, + IOV_DONGLEISOLATION, IOV_VARS +#ifdef SOFTAP + , IOV_FWPATH +#endif }; const bcm_iovar_t dhdsdio_iovars[] = { @@ -1413,6 +1544,7 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 }, + {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, @@ -1420,21 +1552,27 @@ const bcm_iovar_t dhdsdio_iovars[] = { {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, - {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, - {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, - {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, #ifdef DHD_DEBUG {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, + {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, + {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, + {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, +#ifdef DHD_DEBUG + {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, +#endif /* DHD_DEBUG */ #endif /* DHD_DEBUG */ #ifdef SDTEST {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, #endif /* SDTEST */ - + {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, +#ifdef SOFTAP + {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, +#endif {NULL, 0, 0, 0, 0 } }; @@ -1460,8 +1598,8 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "Bus SDIO structure:\n"); bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", bus->hostintmask, bus->intstatus, bus->sdpcm_ver); - bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d rxskip %d rxlen %d rx_seq %d\n", - bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->rxskip, + bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", + bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, bus->rxlen, bus->rx_seq); bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); @@ -1646,18 +1784,314 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s sdaddr = 0; dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); } + } xfer_done: /* Return the window to backplane enumeration space for core access */ if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { - DHD_ERROR(("%s: FAILED to return to 0x%x\n", __FUNCTION__, + DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, bcmsdh_cur_sbwad(bus->sdh))); } return bcmerror; } +#ifdef DHD_DEBUG +static int +dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) +{ + uint32 addr; + int rv; + + /* Read last word in memory to determine address of sdpcm_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0) + return rv; + + addr = ltoh32(addr); + + DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); + + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { + DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr)); + return BCME_ERROR; + } + + /* Read hndrte_shared structure */ + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) + return rv; + + /* Endianness */ + sh->flags = ltoh32(sh->flags); + sh->trap_addr = ltoh32(sh->trap_addr); + sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); + sh->assert_file_addr = ltoh32(sh->assert_file_addr); + sh->assert_line = ltoh32(sh->assert_line); + sh->console_addr = ltoh32(sh->console_addr); + sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { + DHD_ERROR(("%s: sdpcm_shared version %d in dhd " + "is different than sdpcm_shared version %d in dongle\n", + __FUNCTION__, SDPCM_SHARED_VERSION, + sh->flags & SDPCM_SHARED_VERSION_MASK)); + return BCME_ERROR; + } + + return BCME_OK; +} + +#define CONSOLE_LINE_MAX 192 + +static int +dhdsdio_readconsole(dhd_bus_t *bus) +{ + dhd_console_t *c = &bus->console; + uint8 line[CONSOLE_LINE_MAX], ch; + uint32 n, idx, addr; + int rv; + + /* Don't do anything until FWREADY updates console address */ + if (bus->console_addr == 0) + return 0; + + /* Read console log struct */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) + return rv; + + /* Allocate console buffer (one time only) */ + if (c->buf == NULL) { + c->bufsize = ltoh32(c->log.buf_size); + if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) + return BCME_NOMEM; + } + + idx = ltoh32(c->log.idx); + + /* Protect against corrupt value */ + if (idx > c->bufsize) + return BCME_ERROR; + + /* Skip reading the console buffer if the index pointer has not moved */ + if (idx == c->last) + return BCME_OK; + + /* Read the console buffer */ + addr = ltoh32(c->log.buf); + if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) + return rv; + + while (c->last != idx) { + for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { + if (c->last == idx) { + /* This would output a partial line. Instead, back up + * the buffer pointer and output this line next time around. + */ + if (c->last >= n) + c->last -= n; + else + c->last = c->bufsize - n; + goto break2; + } + ch = c->buf[c->last]; + c->last = (c->last + 1) % c->bufsize; + if (ch == '\n') + break; + line[n] = ch; + } + + if (n > 0) { + if (line[n - 1] == '\r') + n--; + line[n] = 0; + printf("CONSOLE: %s\n", line); + } + } +break2: + + return BCME_OK; +} + +static int +dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) +{ + int bcmerror = 0; + uint msize = 512; + char *mbuffer = NULL; + uint maxstrlen = 256; + char *str = NULL; + trap_t tr; + sdpcm_shared_t sdpcm_shared; + struct bcmstrbuf strbuf; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + if (data == NULL) { + /* + * Called after a rx ctrl timeout. "data" is NULL. + * allocate memory to trace the trap or assert. + */ + size = msize; + mbuffer = data = MALLOC(bus->dhd->osh, msize); + if (mbuffer == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); + bcmerror = BCME_NOMEM; + goto done; + } + } + + if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { + DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); + bcmerror = BCME_NOMEM; + goto done; + } + + if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) + goto done; + + bcm_binit(&strbuf, data, size); + + bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", + sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); + + if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); + } + + if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { + /* NOTE: Misspelled assert is intentional - DO NOT FIX. + * (Avoids conflict with real asserts for programmatic parsing of output.) + */ + bcm_bprintf(&strbuf, "No trap%s in dongle", + (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) + ?"/assrt" :""); + } else { + if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { + /* Download assert */ + bcm_bprintf(&strbuf, "Dongle assert"); + if (sdpcm_shared.assert_exp_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_exp_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " expr \"%s\"", str); + } + + if (sdpcm_shared.assert_file_addr != 0) { + str[0] = '\0'; + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.assert_file_addr, + (uint8 *)str, maxstrlen)) < 0) + goto done; + + str[maxstrlen - 1] = '\0'; + bcm_bprintf(&strbuf, " file \"%s\"", str); + } + + bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); + } + + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + if ((bcmerror = dhdsdio_membytes(bus, FALSE, + sdpcm_shared.trap_addr, + (uint8*)&tr, sizeof(trap_t))) < 0) + goto done; + + bcm_bprintf(&strbuf, + "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "lp 0x%x, rpc 0x%x Trap offset 0x%x, " + "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n", + ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), + ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), + ltoh32(sdpcm_shared.trap_addr), + ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), + ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); + } + } + + if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { + DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); + } + +#ifdef DHD_DEBUG + if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); + } +#endif /* DHD_DEBUG */ + +done: + if (mbuffer) + MFREE(bus->dhd->osh, mbuffer, msize); + if (str) + MFREE(bus->dhd->osh, str, maxstrlen); + + return bcmerror; +} + +static int +dhdsdio_mem_dump(dhd_bus_t *bus) +{ + int ret = 0; + int size; /* Full mem size */ + int start = 0; /* Start address */ + int read_size = 0; /* Read size of each iteration */ + uint8 *buf = NULL, *databuf = NULL; + + /* Get full mem size */ + size = bus->ramsize; + buf = MALLOC(bus->dhd->osh, size); + if (!buf) { + printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size); + return -1; + } + + /* Read mem content */ + printf("Dump dongle memory"); + databuf = buf; + while (size) + { + read_size = MIN(MEMBLOCK, size); + if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) + { + printf("%s: Error membytes %d\n", __FUNCTION__, ret); + if (buf) { + MFREE(bus->dhd->osh, buf, size); + } + return -1; + } + printf("."); + + /* Decrement size and increment start address */ + size -= read_size; + start += read_size; + databuf += read_size; + } + printf("Done\n"); + + /* free buf before return !!! */ + if (write_to_file(bus->dhd, buf, bus->ramsize)) + { + printf("%s: Error writing to files\n", __FUNCTION__); + return -1; + } + + /* buf free handled in write_to_file, not here */ + return 0; +} +#endif /* defined(DHD_DEBUG) */ + int dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) { @@ -1692,6 +2126,57 @@ err: return bcmerror; } +#ifdef DHD_DEBUG + +#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) +static int +dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) +{ + int int_val; + uint32 addr, data; + + + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); + data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); + *bcmerror = 0; + + bcmsdh_reg_write(bus->sdh, addr, 4, 1); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + int_val = bcmsdh_reg_read(bus->sdh, data, 4); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (!set) + return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB); + if (enable) + int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB; + else + int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB; + bcmsdh_reg_write(bus->sdh, data, 4, int_val); + if (bcmsdh_regfail(bus->sdh)) { + *bcmerror = BCME_SDIO_ERROR; + return -1; + } + if (bus->sih->chip == BCM4330_CHIP_ID) { + uint32 chipcontrol; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); + chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); + chipcontrol &= ~0x8; + if (enable) { + chipcontrol |= 0x8; + chipcontrol &= ~0x3; + } + bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); + } + + return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB); +} +#endif + static int dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, void *params, int plen, void *arg, int len, int val_size) @@ -1830,11 +2315,35 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch /* If we know about SOCRAM, check for a fit */ if ((bus->orig_ramsize) && - ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) { - DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", - __FUNCTION__, bus->orig_ramsize, size, address)); - bcmerror = BCME_BADARG; - break; + ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) + { + uint8 enable, protect; + si_socdevram(bus->sih, FALSE, &enable, &protect); + if (!enable || protect) { + DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", + __FUNCTION__, bus->orig_ramsize, size, address)); + DHD_ERROR(("%s: socram enable %d, protect %d\n", + __FUNCTION__, enable, protect)); + bcmerror = BCME_BADARG; + break; + } + if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) { + uint32 devramsize = si_socdevram_size(bus->sih); + if ((address < SOCDEVRAM_4330_ARM_ADDR) || + (address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) { + DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", + __FUNCTION__, address, size)); + DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", + __FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize)); + bcmerror = BCME_BADARG; + break; + } + /* move it such that address is real now */ + address -= SOCDEVRAM_4330_ARM_ADDR; + address += SOCDEVRAM_4330_BP_ADDR; + DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", + __FUNCTION__, (set ? "write" : "read"), size, address)); + } } /* Generate the actual data pointer */ @@ -1865,6 +2374,10 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch bcmerror = dhdsdio_download_state(bus, bool_val); break; + case IOV_SVAL(IOV_SOCRAM_STATE): + bcmerror = dhdsdio_download_state(bus, bool_val); + break; + case IOV_SVAL(IOV_VARS): bcmerror = dhdsdio_downloadvars(bus, arg, len); break; @@ -1914,7 +2427,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; #endif /* DHD_DEBUG */ - +#ifdef DHD_DEBUG case IOV_GVAL(IOV_SDREG): { sdreg_t *sd_ptr; @@ -1983,11 +2496,11 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch *(char *)arg = 0; bcmstrcat(arg, "\nFunc 0\n"); - bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); bcmstrcat(arg, "\nFunc 1\n"); - bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); bcmstrcat(arg, "\nFunc 2\n"); - bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); break; } @@ -2026,7 +2539,20 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_SVAL(IOV_TXMINMAX): dhd_txminmax = (uint)int_val; break; -#ifdef DHD_DEBUG + + case IOV_GVAL(IOV_SERIALCONS): + int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); + if (bcmerror != 0) + break; + + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_SERIALCONS): + dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); + break; + + #endif /* DHD_DEBUG */ @@ -2051,6 +2577,15 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch #endif /* SDTEST */ + case IOV_GVAL(IOV_DONGLEISOLATION): + int_val = bus->dhd->dongle_isolation; + bcopy(&int_val, arg, val_size); + break; + + case IOV_SVAL(IOV_DONGLEISOLATION): + bus->dhd->dongle_isolation = bool_val; + break; + case IOV_SVAL(IOV_DEVRESET): DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", __FUNCTION__, bool_val, bus->dhd->dongle_reset, @@ -2062,7 +2597,47 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch dhd_bus_devreset(bus->dhd, (uint8)bool_val); break; - +#ifdef SOFTAP + case IOV_GVAL(IOV_FWPATH): + { + uint32 fw_path_len; + + fw_path_len = strlen(bus->fw_path); + + DHD_INFO(("[softap] get fwpath, l=%d\n", len)); + + if ( fw_path_len > len-1 ) { + bcmerror = BCME_BUFTOOSHORT; + break; + } + + if ( fw_path_len ) + bcopy(bus->fw_path, arg, fw_path_len); + + ((uchar*)arg)[fw_path_len] = 0; + } + break; + + case IOV_SVAL(IOV_FWPATH): + { + DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val)); + + switch(int_val) { + case 1: + bus->fw_path = fw_path; /* ordinary one */ + break; + case 2: + bus->fw_path = fw_path2; + break; + default: + bcmerror = BCME_BADARG; + return bcmerror; + } + + DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0]?bus->fw_path:"NULL"))); + } + break; +#endif case IOV_GVAL(IOV_DEVRESET): DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); @@ -2085,6 +2660,9 @@ exit: dhd_os_sdunlock(bus->dhd); + if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE) + dhd_preinit_ioctls((dhd_pub_t *) bus->dhd); + return bcmerror; } @@ -2094,15 +2672,26 @@ dhdsdio_write_vars(dhd_bus_t *bus) int bcmerror = 0; uint32 varsize; uint32 varaddr; - char *vbuffer; + uint8 *vbuffer; uint32 varsizew; +#ifdef DHD_DEBUG + uint8 *nvram_ularray; +#endif /* DHD_DEBUG */ /* Even if there are no vars are to be written, we still need to set the ramsize. */ varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; varaddr = (bus->ramsize - 4) - varsize; if (bus->vars) { - vbuffer = (char*)MALLOC(bus->dhd->osh, varsize); + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { + if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { + DHD_ERROR(("PR85623WAR in place\n")); + varsize += 4; + varaddr -= 4; + } + } + + vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); if (!vbuffer) return BCME_NOMEM; @@ -2111,6 +2700,31 @@ dhdsdio_write_vars(dhd_bus_t *bus) /* Write the vars list */ bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); +#ifdef DHD_DEBUG + /* Verify NVRAM bytes */ + DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); + nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); + if (!nvram_ularray) + return BCME_NOMEM; + + /* Upload image to verify downloaded contents. */ + memset(nvram_ularray, 0xaa, varsize); + + /* Read the vars list to temp buffer for comparison */ + bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", + __FUNCTION__, bcmerror, varsize, varaddr)); + } + /* Compare the org NVRAM with the one read from RAM */ + if (memcmp(vbuffer, nvram_ularray, varsize)) { + DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); + } else + DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", + __FUNCTION__)); + + MFREE(bus->dhd->osh, nvram_ularray, varsize); +#endif /* DHD_DEBUG */ MFREE(bus->dhd->osh, vbuffer, varsize); } @@ -2153,7 +2767,6 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) * To exit download state, simply reset ARM (default is RAM boot). */ if (enter) { - bus->alp_only = TRUE; if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && @@ -2185,7 +2798,10 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) /* Clear the top bit of memory */ if (bus->ramsize) { uint32 zeros = 0; - dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4); + if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } } } else { if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { @@ -2201,8 +2817,8 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) } if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: no vars written to RAM\n", __FUNCTION__)); - bcmerror = 0; + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; } if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && @@ -2233,6 +2849,7 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) bus->dhd->busstate = DHD_BUS_LOAD; } + fail: /* Always return to SDIOD core */ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) @@ -2349,19 +2966,27 @@ exit: void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) { - osl_t *osh = bus->dhd->osh; + osl_t *osh; uint32 local_hostintmask; uint8 saveclk; uint retries; int err; + if (!bus->dhd) + return; + osh = bus->dhd->osh; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + bcmsdh_waitlockfree(NULL); + if (enforce_mutex) dhd_os_sdlock(bus->dhd); BUS_WAKE(bus); + /* Change our idea of bus state */ + bus->dhd->busstate = DHD_BUS_DOWN; + /* Enable clock for device interrupts */ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); @@ -2370,9 +2995,6 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) local_hostintmask = bus->hostintmask; bus->hostintmask = 0; - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; - /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); if (!err) { @@ -2394,11 +3016,8 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) /* Turn off the backplane clock (only) */ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); - /* Clear the data packet queues */ - pktq_flush(osh, &bus->txq, TRUE); + pktq_flush(osh, &bus->txq, TRUE, NULL, 0); /* Clear any held glomming stuff */ if (bus->glomd) @@ -2416,14 +3035,17 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) /* Reset some F2 state stuff */ bus->rxskip = FALSE; bus->tx_seq = bus->rx_seq = 0; + + if (enforce_mutex) + dhd_os_sdunlock(bus->dhd); } int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) { dhd_bus_t *bus = dhdp->bus; + dhd_timeout_t tmo; uint retries = 0; - uint8 ready, enable; int err, ret = 0; uint8 saveclk; @@ -2439,8 +3061,11 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) /* Make sure backplane clock is on, needed to generate F2 interrupt */ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (bus->clkstate != CLK_AVAIL) + if (bus->clkstate != CLK_AVAIL) { + DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); goto exit; + } + /* Force clocks on backplane to be sure F2 interrupt propagates */ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -2461,26 +3086,32 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); /* Give the dongle some time to do its thing and set IOR2 */ - retries = DHD_WAIT_F2RDY; - while ((enable != - ((ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL)))) && - retries--) { - OSL_DELAY(1000); - } + dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); + ready = 0; + while (ready != enable && !dhd_timeout_expired(&tmo)) + ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); - retries = 0; - DHD_INFO(("%s: enable 0x%02x, ready 0x%02x\n", __FUNCTION__, enable, ready)); + DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", + __FUNCTION__, enable, ready, tmo.elapsed)); + /* If F2 successfully enabled, set core and enable interrupts */ if (ready == enable) { /* Make sure we're talking to the core. */ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); + ASSERT(bus->regs != NULL); /* Set up the interrupt mask and enable interrupts */ bus->hostintmask = HOSTINTMASK; + /* corerev 4 could use the newer interrupt logic to detect the frames */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && + (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { + bus->hostintmask &= ~I_HMB_FRAME_IND; + bus->hostintmask |= I_XMTDATA_AVAIL; + } W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); @@ -2497,7 +3128,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) } else { DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); bcmsdh_intr_disable(bus->sdh); - } + } } @@ -2515,6 +3146,7 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) /* If we didn't come up, turn off backplane clock */ if (dhdp->busstate != DHD_BUS_DATA) dhdsdio_clkctl(bus, CLK_NONE, FALSE); + exit: if (enforce_mutex) dhd_os_sdunlock(bus->dhd); @@ -2652,7 +3284,7 @@ dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) /* Read remainder of frame body into the rxctl buffer */ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); + (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); @@ -2723,7 +3355,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) dptr += sizeof(uint16); if ((sublen < SDPCM_HDRLEN) || ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { - DHD_ERROR(("%s: desciptor len %d bad: %d\n", + DHD_ERROR(("%s: descriptor len %d bad: %d\n", __FUNCTION__, num, sublen)); pnext = NULL; break; @@ -2809,14 +3441,14 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) */ if (usechain) { errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, (uint8*)PKTDATA(osh, pfirst), - dlen, pfirst, NULL, NULL); + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, (uint8*)PKTDATA(osh, pfirst), + dlen, pfirst, NULL, NULL); } else if (bus->dataptr) { errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, bus->dataptr, - dlen, NULL, NULL, NULL); + bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, + F2SYNC, bus->dataptr, + dlen, NULL, NULL, NULL); sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); if (sublen != dlen) { DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", @@ -3022,7 +3654,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) } continue; } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) { - DHD_ERROR(("%s: rx protocol error\n", dhd_ifname(bus->dhd, ifidx))); + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); bus->dhd->rx_errors++; PKTFREE(osh, pfirst, FALSE); if (plast) { @@ -3053,9 +3685,10 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) dhd_os_sdunlock_rxq(bus->dhd); if (num) { dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num); + dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0); dhd_os_sdlock(bus->dhd); } + bus->rxglomframes++; bus->rxglompkts += num; } @@ -3139,7 +3772,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if ((pad <= bus->roundup) && (pad < bus->blocksize) && ((rdlen + pad + firstread) < MAX_RX_DATASZ)) rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); } @@ -3147,7 +3779,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* We use bus->rxctl buffer in WinXP for initial control pkt receives. * Later we use buffer-poll for data as well as control packets. - * This is required becuase dhd receives full frame in gSPI unlike SDIO. + * This is required because dhd receives full frame in gSPI unlike SDIO. * After the frame is received we have to distinguish whether it is data * or non-data frame. */ @@ -3167,8 +3799,10 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) rxbuf = bus->rxctl; /* Read the entire frame */ sdret = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, NULL, NULL, NULL); + bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + NULL, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); @@ -3201,8 +3835,10 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); rxbuf = (uint8 *)PKTDATA(osh, pkt); /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, pkt, NULL, NULL); + sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), + SDIO_FUNC_2, + F2SYNC, rxbuf, rdlen, + pkt, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); @@ -3212,7 +3848,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) PKTFREE(bus->dhd->osh, pkt, FALSE); bus->dhd->rx_errors++; dhd_os_sdunlock_rxq(bus->dhd); - /* Force retry w/normal header read. Don't attemp NAK for + /* Force retry w/normal header read. Don't attempt NAK for * gSPI */ dhdsdio_rxfail(bus, TRUE, @@ -3266,9 +3902,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Check for consistency with readahead info */ - if (bus->bus == SPI_BUS) - len_consistent = (nextlen != len); - else len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); if (len_consistent) { /* Mismatch, force retry w/normal header (may be >4K) */ @@ -3392,7 +4025,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Read frame header (hardware and software) */ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - bus->rxhdr, firstread, NULL, NULL, NULL); + bus->rxhdr, firstread, NULL, NULL, NULL); bus->f2rxhdrs++; ASSERT(sdret != BCME_PENDING); @@ -3546,7 +4179,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Read the remaining frame data */ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); + ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); @@ -3612,7 +4245,7 @@ deliver: dhd_os_sdunlock_rxq(bus->dhd); continue; } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) { - DHD_ERROR(("%s: rx protocol error\n", dhd_ifname(bus->dhd, ifidx))); + DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); dhd_os_sdlock_rxq(bus->dhd); PKTFREE(bus->dhd->osh, pkt, FALSE); dhd_os_sdunlock_rxq(bus->dhd); @@ -3623,10 +4256,10 @@ deliver: /* Unlock during rx call */ dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, pkt, 1); + dhd_rx_frame(bus->dhd, ifidx, pkt, 1, chan); dhd_os_sdlock(bus->dhd); } - rxcount = maxframes - rxleft; + rxcount = maxframes - rxleft; #ifdef DHD_DEBUG /* Message if we hit the limit */ if (!rxleft && !sdtest) @@ -3666,29 +4299,49 @@ dhdsdio_hostmail(dhd_bus_t *bus) DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); } bus->rxskip = FALSE; - intstatus |= I_HMB_FRAME_IND; + intstatus |= FRAME_AVAIL_MASK(bus); } /* - * Not using DEVREADY or FWREADY at the moment; just print. * DEVREADY does not occur with gSPI. */ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { - bus->sdpcm_ver = (hmb_data >> HMB_DATA_VERSION_SHIFT) & HMB_DATA_VERSION_MASK; + bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT; if (bus->sdpcm_ver != SDPCM_PROT_VERSION) DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", bus->sdpcm_ver, SDPCM_PROT_VERSION)); else DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); + /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { + uint32 val; + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); + + val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); + } + +#ifdef DHD_DEBUG + /* Retrieve console state address now that firmware should have updated it */ + { + sdpcm_shared_t shared; + if (dhdsdio_readshared(bus, &shared) == 0) + bus->console_addr = shared.console_addr; + } +#endif /* DHD_DEBUG */ } /* * Flow Control has been moved into the RX headers and this out of band - * method isn't used any more. Leae this here for possibly remaining backward + * method isn't used any more. Leave this here for possibly remaining backward * compatible with older dongles */ if (hmb_data & HMB_DATA_FC) { - fcbits = (hmb_data >> HMB_DATA_FCDATA_SHIFT) & HMB_DATA_FCDATA_MASK; + fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; if (fcbits & ~bus->flowcontrol) bus->fc_xoff++; @@ -3699,20 +4352,22 @@ dhdsdio_hostmail(dhd_bus_t *bus) bus->flowcontrol = fcbits; } + /* Shouldn't be any others */ if (hmb_data & ~(HMB_DATA_DEVREADY | + HMB_DATA_FWHALT | HMB_DATA_NAKHANDLED | HMB_DATA_FC | HMB_DATA_FWREADY | - (HMB_DATA_FCDATA_MASK << HMB_DATA_FCDATA_SHIFT) | - (HMB_DATA_VERSION_MASK << HMB_DATA_VERSION_SHIFT))) { + HMB_DATA_FCDATA_MASK | + HMB_DATA_VERSION_MASK)) { DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); } return intstatus; } -bool +static bool dhdsdio_dpc(dhd_bus_t *bus) { bcmsdh_info_t *sdh = bus->sdh; @@ -3743,8 +4398,9 @@ dhdsdio_dpc(dhd_bus_t *bus) if (err) { DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); bus->dhd->busstate = DHD_BUS_DOWN; + } else { + ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); } - ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); #endif /* DHD_DEBUG */ /* Read CSR, if clock on switch to AVAIL, else ignore */ @@ -3780,7 +4436,7 @@ dhdsdio_dpc(dhd_bus_t *bus) /* Make sure backplane clock is on */ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - if (bus->clkstate == CLK_PENDING) + if (bus->clkstate != CLK_AVAIL) goto clkwait; /* Pending interrupt indicates new device status */ @@ -3793,8 +4449,12 @@ dhdsdio_dpc(dhd_bus_t *bus) newstatus &= bus->hostintmask; bus->fcstate = !!(newstatus & I_HMB_FC_STATE); if (newstatus) { - W_SDREG(newstatus, ®s->intstatus, retries); bus->f1regdata++; + if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && + (newstatus == I_XMTDATA_AVAIL)) { + } + else + W_SDREG(newstatus, ®s->intstatus, retries); } } @@ -3815,6 +4475,12 @@ dhdsdio_dpc(dhd_bus_t *bus) intstatus |= (newstatus & bus->hostintmask); } + /* Just being here means nothing more to do for chipactive */ + if (intstatus & I_CHIPACTIVE) { + /* ASSERT(bus->clkstate == CLK_AVAIL); */ + intstatus &= ~I_CHIPACTIVE; + } + /* Handle host mailbox indication */ if (intstatus & I_HMB_HOST_INT) { intstatus &= ~I_HMB_HOST_INT; @@ -3844,14 +4510,15 @@ dhdsdio_dpc(dhd_bus_t *bus) } /* Ignore frame indications if rxskip is set */ - if (bus->rxskip) - intstatus &= ~I_HMB_FRAME_IND; + if (bus->rxskip) { + intstatus &= ~FRAME_AVAIL_MASK(bus); + } /* On frame indication, read available frames */ - if (PKT_AVAILABLE()) { + if (PKT_AVAILABLE(bus, intstatus)) { framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); if (rxdone || bus->rxskip) - intstatus &= ~I_HMB_FRAME_IND; + intstatus &= ~FRAME_AVAIL_MASK(bus); rxlimit -= MIN(framecnt, rxlimit); } @@ -3867,11 +4534,52 @@ clkwait: DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", __FUNCTION__, rxdone, framecnt)); bus->intdis = FALSE; +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(1); +#endif /* (OOB_INTR_ONLY) */ bcmsdh_intr_enable(sdh); } + if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { + int ret, i; + + ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, + (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, + NULL, NULL, NULL); + ASSERT(ret != BCME_PENDING); + + if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + + bcmsdh_abort(sdh, SDIO_FUNC_2); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + uint8 hi, lo; + hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + } + if (ret == 0) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + + bus->ctrl_frame_stat = FALSE; + dhd_wait_event_wakeup(bus->dhd); + } /* Send queued frames (limit 1 if rx may still be pending) */ - if ((bus->clkstate != CLK_PENDING) && !bus->fcstate && + else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); framecnt = dhdsdio_sendfromq(bus, framecnt); @@ -3881,15 +4589,15 @@ 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) { - /* Awaiting I_CHIPACTIVE, don't resched */ + /* Awaiting I_CHIPACTIVE; don't resched */ } else if (bus->intstatus || bus->ipend || (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || - PKT_AVAILABLE()) { /* Read multiple frames */ + PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ resched = TRUE; } @@ -3902,23 +4610,34 @@ clkwait: } dhd_os_sdunlock(bus->dhd); - return resched; } bool dhd_bus_dpc(struct dhd_bus *bus) { + bool resched; + /* Call the DPC directly. */ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - return dhdsdio_dpc(bus); + resched = dhdsdio_dpc(bus); + + return resched; } void dhdsdio_isr(void *arg) { dhd_bus_t *bus = (dhd_bus_t*)arg; - bcmsdh_info_t *sdh = bus->sdh; + bcmsdh_info_t *sdh; + + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + + 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__)); @@ -3949,7 +4668,9 @@ dhdsdio_isr(void *arg) #if defined(SDIO_ISR_THREAD) DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - dhdsdio_dpc(bus); + 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); @@ -3973,7 +4694,7 @@ dhdsdio_pktgen_init(dhd_bus_t *bus) /* Default to per-watchdog burst with 10s print time */ bus->pktgen_freq = 1; - bus->pktgen_print = 10000/dhd_watchdog_ms; + bus->pktgen_print = 10000 / dhd_watchdog_ms; bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; /* Default to echo mode */ @@ -4000,8 +4721,10 @@ dhdsdio_pktgen(dhd_bus_t *bus) /* For recv mode, just make sure dongle has started sending */ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (!bus->pktgen_rcvd) - dhdsdio_sdtest_set(bus, TRUE); + if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { + bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; + dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total); + } return; } @@ -4081,7 +4804,7 @@ dhdsdio_pktgen(dhd_bus_t *bus) } static void -dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) +dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count) { void *pkt; uint8 *data; @@ -4097,7 +4820,7 @@ dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) /* Fill in the test header */ *data++ = SDPCM_TEST_SEND; - *data++ = start; + *data++ = count; *data++ = (bus->pktgen_maxlen >> 0); *data++ = (bus->pktgen_maxlen >> 8); @@ -4131,7 +4854,7 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) cmd = *data++; extra = *data++; len = *data++; len += *data++ << 8; - + DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); /* Check length for relevant commands */ if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { if (pktlen != len + SDPCM_TEST_HDRLEN) { @@ -4176,6 +4899,18 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) break; case SDPCM_TEST_DISCARD: + { + int i = 0; + uint8 *prn = data; + uint8 testval = extra; + for (i = 0; i < len; i++) { + if (*prn != testval) { + DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", + i, bus->pktgen_rcvd_rcvsession, testval, *prn)); + prn++; testval++; + } + } + } PKTFREE(osh, pkt, FALSE); bus->pktgen_rcvd++; break; @@ -4189,11 +4924,19 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) break; } - /* For recv mode, stop at limie (and tell dongle to stop sending) */ + /* For recv mode, stop at limit (and tell dongle to stop sending) */ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_total && (bus->pktgen_rcvd >= bus->pktgen_total)) { + if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { + bus->pktgen_rcvd_rcvsession++; + + if (bus->pktgen_total && + (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { bus->pktgen_count = 0; + DHD_ERROR(("Pktgen:rcv test complete!\n")); + bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; dhdsdio_sdtest_set(bus, FALSE); + bus->pktgen_rcvd_rcvsession = 0; + } } } } @@ -4215,6 +4958,9 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (bus->sleeping) return FALSE; + if (dhdp->busstate == DHD_BUS_DOWN) + return FALSE; + dhd_os_sdlock(bus->dhd); /* Poll period: check device if appropriate. */ @@ -4227,8 +4973,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) /* Check device if no interrupts */ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { - if (!bus->dpc_sched || gDK8) - { + if (!bus->dpc_sched) { uint8 devpend; devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTPEND, NULL); @@ -4252,6 +4997,20 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) bus->lastintrs = bus->intrcount; } +#ifdef DHD_DEBUG + /* Poll for console output periodically */ + if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { + bus->console.count += dhd_watchdog_ms; + if (bus->console.count >= dhd_console_ms) { + bus->console.count -= dhd_console_ms; + /* Make sure backplane clock is on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (dhdsdio_readconsole(bus) < 0) + dhd_console_ms = 0; /* On error, stop trying */ + } + } +#endif /* DHD_DEBUG */ + #ifdef SDTEST /* Generate packets if configured */ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { @@ -4264,11 +5023,10 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) /* On idle timeout clear activity flag and/or turn off clock */ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= (uint32)bus->idletime) { + if (++bus->idlecount >= bus->idletime) { bus->idlecount = 0; if (bus->activity) { bus->activity = FALSE; - } else { dhdsdio_clkctl(bus, CLK_NONE, FALSE); } } @@ -4280,6 +5038,68 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } #ifdef DHD_DEBUG +extern int +dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) +{ + dhd_bus_t *bus = dhdp->bus; + uint32 addr, val; + int rv; + void *pkt; + + /* Address could be zero if CONSOLE := 0 in dongle Makefile */ + if (bus->console_addr == 0) + return BCME_UNSUPPORTED; + + /* Exclusive bus access */ + dhd_os_sdlock(bus->dhd); + + /* Don't allow input if dongle is in reset */ + if (bus->dhd->dongle_reset) { + dhd_os_sdunlock(bus->dhd); + return BCME_NOTREADY; + } + + /* Request clock to allow SDIO accesses */ + BUS_WAKE(bus); + /* No pend allowed since txpkt is called later, ht clk has to be on */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + + /* Zero cbuf_index */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); + val = htol32(0); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Write message into cbuf */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) + goto done; + + /* Write length into vcons_in */ + addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); + val = htol32(msglen); + if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) + goto done; + + /* Bump dongle by sending an empty packet on the event channel. + * sdpcm_sendup (RX) checks for virtual console input. + */ + if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) + dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE); + +done: + if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = FALSE; + dhdsdio_clkctl(bus, CLK_NONE, TRUE); + } + + dhd_os_sdunlock(bus->dhd); + + return rv; +} +#endif /* DHD_DEBUG */ + +#ifdef DHD_DEBUG static void dhd_dump_cis(uint fn, uint8 *cis) { @@ -4307,7 +5127,6 @@ dhd_dump_cis(uint fn, uint8 *cis) if ((byte % 16) != 15) DHD_INFO(("\n")); } - #endif /* DHD_DEBUG */ static bool @@ -4319,6 +5138,18 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4315_CHIP_ID) return TRUE; + if (chipid == BCM4319_CHIP_ID) + return TRUE; + if (chipid == BCM4336_CHIP_ID) + return TRUE; + if (chipid == BCM4330_CHIP_ID) + return TRUE; + if (chipid == BCM43237_CHIP_ID) + return TRUE; + if (chipid == BCM43362_CHIP_ID) + return TRUE; + if (chipid == BCM43239_CHIP_ID) + return TRUE; return FALSE; } @@ -4328,6 +5159,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, { int ret; dhd_bus_t *bus; + dhd_cmn_t *cmn; /* Init global variables at run-time, not as part of the declaration. * This is required to support init/de-init of the driver. Initialization @@ -4341,12 +5173,12 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, sd1idle = TRUE; dhd_readahead = TRUE; retrydata = FALSE; - dhd_doflow = FALSE; + dhd_doflow = TRUE; dhd_dongle_memsize = 0; - forcealign = TRUE; + dhd_txminmax = DHD_TXMINMAX; + forcealign = TRUE; - dhd_common_init(); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); @@ -4367,7 +5199,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, DHD_ERROR(("%s: unknown vendor: 0x%04x\n", __FUNCTION__, venid)); return NULL; - break; } /* Check the Device ID and make sure it's one that we support */ @@ -4388,6 +5219,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, case BCM4315_D11A_ID: /* 4315 802.11a id */ DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); break; + case BCM4319_D11N_ID: /* 4319 802.11n id */ + case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ + case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ + DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); + break; case 0: DHD_INFO(("%s: allow device id 0, will check chip internals\n", __FUNCTION__)); @@ -4397,7 +5233,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", __FUNCTION__, venid, devid)); return NULL; - break; } if (osh == NULL) { @@ -4417,11 +5252,19 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, bus->sdh = sdh; bus->cl_devid = (uint16)devid; bus->bus = DHD_BUS; + bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ + /* attach the common module */ + if (!(cmn = dhd_common_init(osh))) { + DHD_ERROR(("%s: dhd_common_init failed\n", __FUNCTION__)); + goto fail; + } + /* attempt to attach to the dongle */ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); + dhd_common_deinit(NULL, cmn); goto fail; } @@ -4431,6 +5274,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, goto fail; } + bus->dhd->cmn = cmn; + cmn->dhd = bus->dhd; + /* Allocate buffers */ if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); @@ -4456,11 +5302,8 @@ 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; } /* Ok, have the per-port tell the stack we're open for business */ @@ -4480,8 +5323,8 @@ static bool dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, uint16 devid) { - uint8 clkctl = 0; int err = 0; + uint8 clkctl = 0; bus->alp_only = TRUE; @@ -4491,8 +5334,9 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, } #ifdef DHD_DEBUG - printf("F1 signature read @0x18000000=0x%4x\n", - bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)); + DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", + bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); + #endif /* DHD_DEBUG */ @@ -4557,9 +5401,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, } #endif /* DHD_DEBUG */ - /* The si_attach() will provide an SI handle, scan the - * backplane. - */ + /* si_attach() will provide an SI handle and scan the backplane */ if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, &bus->vars, &bus->varsz))) { DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); @@ -4574,6 +5416,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } + si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); @@ -4608,17 +5451,25 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, /* Set core control so an SDIO reset does a backplane reset */ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); + bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; - pktq_init(&bus->txq, (PRIOMASK+1), QLEN); - - /* Locate an appropriately-aligned portion of hdrbuf */ - bus->rxhdr = (uint8*)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); + if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && + (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) + { + uint32 val; - if (gDK8) { - dhd_intr = FALSE; - dhd_poll = TRUE; + val = R_REG(osh, &bus->regs->corecontrol); + val &= ~CC_XMTDATAAVAIL_MODE; + val |= CC_XMTDATAAVAIL_CTRL; + W_REG(osh, &bus->regs->corecontrol, val); } + + pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); + + /* Locate an appropriately-aligned portion of hdrbuf */ + bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); + /* Set the poll and/or interrupt flags */ bus->intr = (bool)dhd_intr; if ((bus->poll = (bool)dhd_poll)) @@ -4627,15 +5478,17 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, return TRUE; fail: + if (bus->sih != NULL) + si_detach(bus->sih); return FALSE; } - static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#ifndef DHD_USE_STATIC_BUF if (bus->dhd->maxctl) { bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; if (!(bus->rxbuf = MALLOC(osh, bus->rxblen))) { @@ -4653,6 +5506,22 @@ dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) if (!bus->rxblen) MFREE(osh, bus->rxbuf, bus->rxblen); goto fail; } +#else + if (bus->dhd->maxctl) { + bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; + if (!(bus->rxbuf = dhd_os_prealloc(DHD_PREALLOC_RXBUF, bus->rxblen))) { + DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", + __FUNCTION__, bus->rxblen)); + goto fail; + } + } + /* Allocate buffer to receive glomed packet */ + if (!(bus->databuf = dhd_os_prealloc(DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { + DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", + __FUNCTION__, MAX_DATA_BUF)); + goto fail; + } +#endif /* DHD_USE_STATIC_BUF */ /* Align the buffer */ if ((uintptr)bus->databuf % DHD_SDALIGN) @@ -4666,7 +5535,6 @@ fail: return FALSE; } - static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) { @@ -4750,6 +5618,7 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ret = dhdsdio_download_firmware(bus, osh, bus->sdh); + return ret; } @@ -4759,34 +5628,45 @@ 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; } +/* Detach and free everything */ static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh) { + bool dongle_isolation = FALSE; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (bus) { ASSERT(osh); - /* Detach and free everything */ + /* De-register interrupt handler */ + bcmsdh_intr_disable(bus->sdh); + bcmsdh_intr_dereg(bus->sdh); + if (bus->dhd) { + dhd_common_deinit(bus->dhd, NULL); + dongle_isolation = bus->dhd->dongle_isolation; dhd_detach(bus->dhd); + dhdsdio_release_dongle(bus, osh, dongle_isolation); + dhd_free(bus->dhd); bus->dhd = NULL; } dhdsdio_release_malloc(bus, osh); - dhdsdio_release_dongle(bus, osh); - /* De-register interrupt handler */ - bcmsdh_intr_dereg(bus->sdh); +#ifdef DHD_DEBUG + if (bus->console.buf != NULL) + MFREE(osh, bus->console.buf, bus->console.bufsize); +#endif MFREE(osh, bus, sizeof(dhd_bus_t)); } @@ -4806,37 +5686,54 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) return; if (bus->rxbuf) { +#ifndef DHD_USE_STATIC_BUF MFREE(osh, bus->rxbuf, bus->rxblen); +#endif bus->rxctl = bus->rxbuf = NULL; bus->rxlen = 0; } if (bus->databuf) { +#ifndef DHD_USE_STATIC_BUF MFREE(osh, bus->databuf, MAX_DATA_BUF); +#endif bus->databuf = NULL; } + + if (bus->vars && bus->varsz) { + MFREE(osh, bus->vars, bus->varsz); + bus->vars = NULL; + } + } static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh) +dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation) { - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, + bus->dhd, bus->dhd->dongle_reset)); if (bus->dhd && bus->dhd->dongle_reset) return; if (bus->sih) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + } #if !defined(BCMLXSDMMC) - si_watchdog(bus->sih, 4); + if (dongle_isolation == FALSE) + si_watchdog(bus->sih, 4); #endif /* !defined(BCMLXSDMMC) */ - dhdsdio_clkctl(bus, CLK_NONE, FALSE); + if (bus->dhd) { + dhdsdio_clkctl(bus, CLK_NONE, FALSE); + } si_detach(bus->sih); if (bus->vars && bus->varsz) MFREE(osh, bus->vars, bus->varsz); bus->vars = NULL; } + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } @@ -4888,6 +5785,7 @@ dhdsdio_download_code_array(struct dhd_bus *bus) { int bcmerror = -1; int offset = 0; + unsigned char *ularray = NULL; DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); @@ -4913,7 +5811,48 @@ dhdsdio_download_code_array(struct dhd_bus *bus) } } +#ifdef DHD_DEBUG + /* Upload and compare the downloaded code */ + { + ularray = MALLOC(bus->dhd->osh, bus->ramsize); + /* Upload image to verify downloaded contents. */ + offset = 0; + memset(ularray, 0xaa, bus->ramsize); + while ((offset + MEMBLOCK) < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, MEMBLOCK, offset)); + goto err; + } + + offset += MEMBLOCK; + } + + if (offset < sizeof(dlarray)) { + bcmerror = dhdsdio_membytes(bus, FALSE, offset, + ularray + offset, sizeof(dlarray) - offset); + if (bcmerror) { + DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", + __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); + goto err; + } + } + + if (memcmp(dlarray, ularray, sizeof(dlarray))) { + DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + goto err; + } else + DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", + __FUNCTION__, dlimagename, dlimagever, dlimagedate)); + + } +#endif /* DHD_DEBUG */ + err: + if (ularray) + MFREE(bus->dhd->osh, ularray, bus->ramsize); return bcmerror; } #endif /* BCMEMBEDIMAGE */ @@ -4924,8 +5863,8 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *fw_path) int bcmerror = -1; int offset = 0; uint len; - void * image = NULL; - uint8 * memblock = NULL, * memptr; + void *image = NULL; + uint8 *memblock = NULL, *memptr; DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, fw_path)); @@ -4963,55 +5902,6 @@ err: return bcmerror; } -/* - * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. - * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. - * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. -*/ - -static uint -process_nvram_vars(char *varbuf, uint len) -{ - char *dp; - bool findNewline; - int column; - uint buf_len, n; - - dp = varbuf; - - findNewline = FALSE; - column = 0; - - for (n = 0; n < len; n++) { - if (varbuf[n] == 0) - break; - if (varbuf[n] == '\r') - continue; - if (findNewline && varbuf[n] != '\n') - continue; - findNewline = FALSE; - if (varbuf[n] == '#') { - findNewline = TRUE; - continue; - } - if (varbuf[n] == '\n') { - if (column == 0) - continue; - *dp++ = 0; - column = 0; - continue; - } - *dp++ = varbuf[n]; - column++; - } - buf_len = dp - varbuf; - - while (dp < varbuf + n) - *dp++ = 0; - - return buf_len; -} - /* EXAMPLE: nvram_array nvram_arry format: @@ -5055,27 +5945,29 @@ dhdsdio_download_nvram(struct dhd_bus *bus) goto err; } - memblock = MALLOC(bus->dhd->osh, MEMBLOCK); + memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); if (memblock == NULL) { DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MEMBLOCK)); + __FUNCTION__, MAX_NVRAMBUF_SIZE)); goto err; } /* Download variables */ if (nvram_file_exists) { - len = dhd_os_get_image_block(memblock, MEMBLOCK, image); + len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); } else { len = strlen(bus->nvram_params); - ASSERT(len <= MEMBLOCK); + ASSERT(len <= MAX_NVRAMBUF_SIZE); memcpy(memblock, bus->nvram_params, len); } - - if (len > 0 && len < MEMBLOCK) { + if (len > 0 && len < MAX_NVRAMBUF_SIZE) { bufp = (char *)memblock; bufp[len] = 0; len = process_nvram_vars(bufp, len); + if (len % 4) { + len += 4 - (len % 4); + } bufp += len; *bufp++ = 0; if (len) @@ -5093,7 +5985,7 @@ dhdsdio_download_nvram(struct dhd_bus *bus) err: if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK); + MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); if (image) dhd_os_close_image(image); @@ -5114,7 +6006,7 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) #ifdef BCMEMBEDIMAGE embed = TRUE; #else - return bcmerror; + return 0; #endif } @@ -5182,8 +6074,8 @@ dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf { int status; - /* 4329: GSPI check */ status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); + return status; } @@ -5229,24 +6121,27 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (flag == TRUE) { if (!bus->dhd->dongle_reset) { - + dhd_os_sdlock(dhdp); + dhd_os_wd_timer(dhdp, 0); #if !defined(IGNORE_ETH0_DOWN) /* Force flow control as protection when stop come before ifconfig_down */ - dhd_txflowcontrol(bus->dhd, 0, ON); + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); #endif /* !defined(IGNORE_ETH0_DOWN) */ - - /* save country settinng if was pre-setup with priv ioctl */ - dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY, - bus->dhd->country_code, sizeof(bus->dhd->country_code)); /* Expect app to have torn down any connection before calling */ /* Stop the bus, disable F2 */ dhd_bus_stop(bus, FALSE); +#if defined(OOB_INTR_ONLY) + /* Clean up any pending IRQ */ + bcmsdh_set_irq(FALSE); +#endif /* defined(OOB_INTR_ONLY) */ + /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh); + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE); bus->dhd->dongle_reset = TRUE; bus->dhd->up = FALSE; + dhd_os_sdunlock(dhdp); DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); /* App can now remove power from device */ @@ -5259,6 +6154,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (bus->dhd->dongle_reset) { /* Turn on WLAN */ + dhd_os_sdlock(dhdp); + /* Reset SD client */ bcmsdh_reset(bus->sdh); @@ -5271,10 +6168,11 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { /* Re-init bus, enable F2 transfer */ - dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); - + bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); + if (bcmerror == BCME_OK) { #if defined(OOB_INTR_ONLY) - dhd_enable_oob_intr(bus, TRUE); + bcmsdh_set_irq(TRUE); + dhd_enable_oob_intr(bus, TRUE); #endif /* defined(OOB_INTR_ONLY) */ bus->dhd->dongle_reset = FALSE; @@ -5282,14 +6180,21 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) #if !defined(IGNORE_ETH0_DOWN) /* Restore flow control */ - dhd_txflowcontrol(bus->dhd, 0, OFF); + dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); #endif + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); + } else { + dhd_bus_stop(bus, FALSE); + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE); + } } else bcmerror = BCME_SDIO_ERROR; } else bcmerror = BCME_SDIO_ERROR; + + dhd_os_sdunlock(dhdp); } else { bcmerror = BCME_NOTDOWN; DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n", @@ -5299,3 +6204,12 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) } return bcmerror; } + +int +dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) +{ + dhd_bus_t *bus; + + bus = dhdp->bus; + return dhdsdio_membytes(bus, set, address, data, size); +} diff --git a/src/dhd/sys/dhd_wlfc.h b/src/dhd/sys/dhd_wlfc.h new file mode 100644 index 0000000..53db62c --- /dev/null +++ b/src/dhd/sys/dhd_wlfc.h @@ -0,0 +1,248 @@ +/* +* Copyright (C) 1999-2011, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* 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: dhd_wlfc.h,v 1.1.8.1 2010-09-09 22:41:08 Exp $ +* +*/ +#ifndef __wlfc_host_driver_definitions_h__ +#define __wlfc_host_driver_definitions_h__ + +/* 16 bits will provide an absolute max of 65536 slots */ +#define WLFC_HANGER_MAXITEMS 1024 + +#define WLFC_HANGER_ITEM_STATE_FREE 1 +#define WLFC_HANGER_ITEM_STATE_INUSE 2 + +#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ +#define WLFC_PKTID_HSLOT_SHIFT 8 + +/* x -> TXSTATUS TAG to/from firmware */ +#define WLFC_PKTID_HSLOT_GET(x) \ + (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK) +#define WLFC_PKTID_HSLOT_SET(var, slot) \ + ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \ + (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT)) + +#define WLFC_PKTID_FREERUNCTR_MASK 0xff + +#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK) +#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \ + ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \ + (((ctr) & WLFC_PKTID_FREERUNCTR_MASK)))) + +#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \ + NULL : pktq_penq((pq), (prec), (p))) +#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \ + NULL : pktq_penq_head((pq), (prec), (p))) + +typedef enum ewlfc_packet_state { + eWLFC_PKTTYPE_NEW, + eWLFC_PKTTYPE_DELAYED, + eWLFC_PKTTYPE_SUPPRESSED, + eWLFC_PKTTYPE_MAX +} ewlfc_packet_state_t; + +typedef enum ewlfc_mac_entry_action { + eWLFC_MAC_ENTRY_ACTION_ADD, + eWLFC_MAC_ENTRY_ACTION_DEL, + eWLFC_MAC_ENTRY_ACTION_MAX +} ewlfc_mac_entry_action_t; + +typedef struct wlfc_hanger_item { + uint8 state; + uint8 pad[3]; + uint32 identifier; + void* pkt; +#ifdef PROP_TXSTATUS_DEBUG + uint32 push_time; +#endif +} wlfc_hanger_item_t; + +typedef struct wlfc_hanger { + int max_items; + uint32 pushed; + uint32 popped; + uint32 failed_to_push; + uint32 failed_to_pop; + uint32 failed_slotfind; + wlfc_hanger_item_t items[1]; +} wlfc_hanger_t; + +#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ + sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) + +#define WLFC_STATE_OPEN 1 +#define WLFC_STATE_CLOSE 2 + +#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ +#define WLFC_PSQ_LEN 64 +#define WLFC_SENDQ_LEN 256 + +#define WLFC_FLOWCONTROL_DELTA 8 +#define WLFC_FLOWCONTROL_HIWATER (WLFC_PSQ_LEN - WLFC_FLOWCONTROL_DELTA) +#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER - WLFC_FLOWCONTROL_DELTA) + +typedef struct wlfc_mac_descriptor { + uint8 occupied; + uint8 interface_id; + uint8 iftype; + uint8 state; + uint8 ac_bitmap; /* for APSD */ + uint8 requested_credit; + uint8 requested_packet; + uint8 ea[ETHER_ADDR_LEN]; + /* + maintain (MAC,AC) based seq count for + packets going to the device. As well as bc/mc. + */ + uint8 seq[AC_COUNT + 1]; + uint8 generation; + struct pktq psq; + /* The AC pending bitmap that was reported to the fw at last change */ + uint8 traffic_lastreported_bmp; + /* The new AC pending bitmap */ + uint8 traffic_pending_bmp; + /* 1= send on next opportunity */ + uint8 send_tim_signal; + uint8 mac_handle; +#ifdef PROP_TXSTATUS_DEBUG + uint32 dstncredit_sent_packets; + uint32 dstncredit_acks; + uint32 opened_ct; + uint32 closed_ct; +#endif +} wlfc_mac_descriptor_t; + +#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ + entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) + +#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ +#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] + +typedef struct athost_wl_stat_counters { + uint32 pktin; + uint32 pkt2bus; + uint32 pktdropped; + uint32 tlv_parse_failed; + uint32 rollback; + uint32 rollback_failed; + uint32 sendq_full_error; + uint32 delayq_full_error; + uint32 credit_request_failed; + uint32 packet_request_failed; + uint32 mac_update_failed; + uint32 psmode_update_failed; + uint32 interface_update_failed; + uint32 wlfc_header_only_pkt; + uint32 txstatus_in; + uint32 d11_suppress; + uint32 wl_suppress; + uint32 bad_suppress; + uint32 pkt_freed; + uint32 pkt_free_err; + uint32 psq_wlsup_retx; + uint32 psq_wlsup_enq; + uint32 psq_d11sup_retx; + uint32 psq_d11sup_enq; + uint32 psq_hostq_retx; + uint32 psq_hostq_enq; + uint32 mac_handle_notfound; + uint32 wlc_tossed_pkts; + uint32 dhd_hdrpulls; + uint32 generic_error; + /* an extra one for bc/mc traffic */ + uint32 sendq_pkts[AC_COUNT + 1]; +#ifdef PROP_TXSTATUS_DEBUG + /* all pkt2bus -> txstatus latency accumulated */ + uint32 latency_sample_count; + uint32 total_status_latency; + uint32 latency_most_recent; + int idx_delta; + uint32 deltas[10]; + uint32 fifo_credits_sent[6]; + uint32 fifo_credits_back[6]; + uint32 dropped_qfull[6]; + uint32 signal_only_pkts_sent; + uint32 signal_only_pkts_freed; +#endif +} athost_wl_stat_counters_t; + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ + (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ + (ctx)->stats.dropped_qfull[(ac)]++;} while (0) +#else +#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) +#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) +#endif + +#define WLFC_FCMODE_NONE 0 +#define WLFC_FCMODE_IMPLIED_CREDIT 1 +#define WLFC_FCMODE_EXPLICIT_CREDIT 2 + +typedef struct athost_wl_status_info { + uint8 last_seqid_to_wlc; + + /* OSL handle */ + osl_t* osh; + /* dhd pub */ + void* dhdp; + + /* stats */ + athost_wl_stat_counters_t stats; + + /* the additional ones are for bc/mc and ATIM FIFO */ + int FIFO_credit[AC_COUNT + 2]; + struct pktq SENDQ; + + /* packet hanger and MAC->handle lookup table */ + void* hanger; + struct { + /* table for individual nodes */ + wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; + /* table for interfaces */ + wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; + /* OS may send packets to unknown (unassociated) destinations */ + /* A place holder for bc/mc and packets to unknown destinations */ + wlfc_mac_descriptor_t other; + } destination_entries; + /* token position for different priority packets */ + uint8 token_pos[AC_COUNT]; + /* ON/OFF state for flow control to the host network interface */ + uint8 hostif_flow_state[WLFC_MAX_IFNUM]; + uint8 host_ifidx; + /* to flow control an OS interface */ + uint8 toggle_host_if; + + /* + Mode in which the dhd flow control shall operate. Must be set before + traffic starts to the device. + 0 - Do not do any proptxtstatus flow control + 1 - Use implied credit from a packet status + 2 - Use explicit credit + */ + uint8 proptxstatus_mode; +} athost_wl_status_info_t; + +#endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/src/dongle/dngl_stats.h b/src/dongle/dngl_stats.h index 3e42530..9cdf718 100644 --- a/src/dongle/dngl_stats.h +++ b/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-2011, 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: dngl_stats.h,v 1.2.140.3 2008/05/26 16:52:08 Exp $ + * $Id: dngl_stats.h,v 1.5 2008-06-02 16:56:20 Exp $ */ #ifndef _dngl_stats_h_ diff --git a/src/dongle/dngl_wlhdr.h b/src/dongle/dngl_wlhdr.h new file mode 100644 index 0000000..8b39b9e --- /dev/null +++ b/src/dongle/dngl_wlhdr.h @@ -0,0 +1,40 @@ +/* + * Dongle WL Header definitions + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: dngl_wlhdr.h,v 1.1 2009-01-08 01:21:12 Exp $ + */ + +#ifndef _dngl_wlhdr_h_ +#define _dngl_wlhdr_h_ + +typedef struct wl_header { + uint8 type; /* Header type */ + uint8 version; /* Header version */ + int8 rssi; /* RSSI */ + uint8 pad; /* Unused */ +} wl_header_t; + +#define WL_HEADER_LEN sizeof(wl_header_t) +#define WL_HEADER_TYPE 0 +#define WL_HEADER_VER 1 +#endif /* _dngl_wlhdr_h_ */ diff --git a/src/include/Makefile b/src/include/Makefile index 439ead1..c07266f 100644 --- a/src/include/Makefile +++ b/src/include/Makefile @@ -1,21 +1,53 @@ +#!/bin/bash # -# include/Makefile +# This script serves following purpose: +# +# 1. It generates native version information by querying +# automerger maintained database to see where src/include +# came from +# 2. For select components, as listed in compvers.sh +# it generates component version files # # Copyright 2005, Broadcom, Inc. # -# $Id: Makefile,v 13.5 2005/02/17 19:11:31 Exp $ +# $Id: Makefile 241702 2011-02-19 00:41:03Z automrgr $ # -SRCBASE = .. +SRCBASE := .. + +TARGETS := epivers.h -TARGETS = epivers.h +ifdef VERBOSE +export VERBOSE +endif +all release: epivers compvers -all release: +# Generate epivers.h for native branch version +epivers: bash epivers.sh +# Generate epivers.h for native branch version +compvers: + @if [ -s "compvers.sh" ]; then \ + echo "Generating component versions, if any"; \ + bash compvers.sh; \ + else \ + echo "Skipping component version generation"; \ + fi + +# Generate epivers.h for native branch version +clean_compvers: + @if [ -s "compvers.sh" ]; then \ + echo "bash compvers.sh clean"; \ + bash compvers.sh clean; \ + else \ + echo "Skipping component version clean"; \ + fi + clean: - rm -rf ${TARGETS} *.prev + rm -f $(TARGETS) *.prev +clean_all: clean clean_compvers -.PHONY: all release clean +.PHONY: all release clean epivers compvers clean_compvers diff --git a/src/include/aidmp.h b/src/include/aidmp.h index fa542cf..375df44 100644 --- a/src/include/aidmp.h +++ b/src/include/aidmp.h @@ -1,7 +1,7 @@ /* * Broadcom AMBA Interconnect definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: aidmp.h,v 13.2.10.1 2008/05/07 20:32:12 Exp $ + * $Id: aidmp.h,v 13.4.14.1 2010-03-09 18:40:06 Exp $ */ @@ -303,14 +303,19 @@ typedef volatile struct _aidmp { #define AI_OOBDEXTWIDTH 0x360 #define AI_OOBDINWIDTH 0x364 #define AI_OOBDOUTWIDTH 0x368 + + #define AI_IOCTRLSET 0x400 #define AI_IOCTRLCLEAR 0x404 #define AI_IOCTRL 0x408 #define AI_IOSTATUS 0x500 -#define AI_IOCTRLWIDTH 0x700 -#define AI_IOSTATUSWIDTH 0x704 #define AI_RESETCTRL 0x800 #define AI_RESETSTATUS 0x804 + + +#define AI_IOCTRLWIDTH 0x700 +#define AI_IOSTATUSWIDTH 0x704 + #define AI_RESETREADID 0x808 #define AI_RESETWRITEID 0x80c #define AI_ERRLOGCTRL 0xa00 @@ -365,4 +370,8 @@ typedef volatile struct _aidmp { #define AICFG_ERRL 0x00000002 #define AICFG_RST 0x00000001 + +#define OOB_SEL_OUTEN_B_5 15 +#define OOB_SEL_OUTEN_B_6 23 + #endif diff --git a/src/include/bcmcdc.h b/src/include/bcmcdc.h index 8459317..ce45c50 100644 --- a/src/include/bcmcdc.h +++ b/src/include/bcmcdc.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,77 +24,98 @@ * 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: bcmcdc.h,v 13.14.16.4.2.2 2008/10/31 23:21:24 Exp $ + * $Id: bcmcdc.h,v 13.25.10.3 2010-12-22 23:47:26 Exp $ */ + +#ifndef _bcmcdc_h_ +#define _bcmcdc_h_ #include <proto/ethernet.h> typedef struct cdc_ioctl { - uint32 cmd; /* ioctl command value */ - uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ - uint32 flags; /* flag defns given below */ - uint32 status; /* status code returned from the device */ + uint32 cmd; + uint32 len; + uint32 flags; + uint32 status; } cdc_ioctl_t; -/* Max valid buffer size that can be sent to the dongle */ + #define CDC_MAX_MSG_SIZE ETHER_MAX_LEN -/* len field is divided into input and output buffer lengths */ -#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ - /* excluding IOCTL header */ + +#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF + #define CDCL_IOC_OUTLEN_SHIFT 0 -#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ +#define CDCL_IOC_INLEN_MASK 0xFFFF0000 #define CDCL_IOC_INLEN_SHIFT 16 -/* CDC flag definitions */ -#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ -#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ -#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ + +#define CDCF_IOC_ERROR 0x01 +#define CDCF_IOC_SET 0x02 +#define CDCF_IOC_OVL_IDX_MASK 0x3c +#define CDCF_IOC_OVL_RSV 0x40 +#define CDCF_IOC_OVL 0x80 +#define CDCF_IOC_ACTION_MASK 0xfe +#define CDCF_IOC_ACTION_SHIFT 1 +#define CDCF_IOC_IF_MASK 0xF000 #define CDCF_IOC_IF_SHIFT 12 -#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ -#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ +#define CDCF_IOC_ID_MASK 0xFFFF0000 +#define CDCF_IOC_ID_SHIFT 16 -/* Convenient extraction of message ID */ #define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) #define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) -#define CDC_GET_IF_IDX(hdr) (((hdr->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) + +#define CDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) #define CDC_SET_IF_IDX(hdr, idx) \ - (hdr->flags = ((hdr->flags & ~CDCF_IOC_IF_MASK) | \ - (CDCF_IOC_IF_MASK & (idx << CDCF_IOC_IF_SHIFT)))) + ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) + -/* - * BDC header - * - * The BDC header is used on data packets to convey priority across USB. - */ #define BDC_HEADER_LEN 4 -#define BDC_PROTO_VER 1 /* Protocol version */ +#define BDC_PROTO_VER_1 1 +#define BDC_PROTO_VER 2 -#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ +#define BDC_FLAG_VER_MASK 0xf0 +#define BDC_FLAG_VER_SHIFT 4 -#ifndef EXT_STA -#define BDC_FLAG__UNUSED 0x03 /* Unassigned */ -#else -#define BDC_FLAG_EXEMPT 0x03 /* Vista/EXT_STA: use for encryption exemption */ -#endif /* EXT_STA */ -#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ -#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ +#define BDC_FLAG__UNUSED 0x03 +#define BDC_FLAG_SUM_GOOD 0x04 +#define BDC_FLAG_SUM_NEEDED 0x08 #define BDC_PRIORITY_MASK 0x7 -#define BDC_FLAG2_IF_MASK 0x0f /* APSTA: interface on which the packet was received */ +#define BDC_FLAG2_FC_FLAG 0x10 + +#define BDC_PRIORITY_FC_SHIFT 4 + +#define BDC_FLAG2_IF_MASK 0x0f #define BDC_FLAG2_IF_SHIFT 0 -/* Convenient extraction of message ID */ -#define BDC_GET_IF_IDX(hdr) (((hdr->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT) +#define BDC_FLAG2_PAD_MASK 0xf0 +#define BDC_FLAG_PAD_MASK 0x03 +#define BDC_FLAG2_PAD_SHIFT 2 +#define BDC_FLAG_PAD_SHIFT 0 +#define BDC_FLAG2_PAD_IDX 0x3c +#define BDC_FLAG_PAD_IDX 0x03 +#define BDC_GET_PAD_LEN(hdr) \ + ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ + ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) +#define BDC_SET_PAD_LEN(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ + (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ + ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ + (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) + +#define BDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) #define BDC_SET_IF_IDX(hdr, idx) \ - (hdr->flags2 = ((hdr->flags2 & ~BDC_FLAG2_IF_MASK) | \ - (BDC_FLAG2_IF_MASK & (idx << BDC_FLAG2_IF_SHIFT)))) + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) struct bdc_header { - uint8 flags; /* Flags */ - uint8 priority; /* 802.1d Priority (low 3 bits) */ + uint8 flags; + uint8 priority; uint8 flags2; - uint8 rssi; + uint8 dataOffset; }; + +#endif diff --git a/src/include/bcmdefs.h b/src/include/bcmdefs.h index 5bd106a..6b92ebc 100644 --- a/src/include/bcmdefs.h +++ b/src/include/bcmdefs.h @@ -1,7 +1,7 @@ /* * Misc system wide definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,8 @@ * 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.20.1 2009/07/09 00:03:10 Exp $ + * + * $Id: bcmdefs.h,v 13.68.2.8 2011-01-08 04:04:19 Exp $ */ @@ -29,12 +30,21 @@ +#define bcmreclaimed 0 +#define _data _data +#define _fn _fn +#define _data _data +#define _fn _fn +#define _fn _fn +#define CONST const +#define BCMFASTPATH -#define bcmreclaimed 0 -#define CONST const +#define _data _data +#define _fn _fn +#define _fn _fn #define STATIC static @@ -45,6 +55,7 @@ #define JTAG_BUS 4 #define USB_BUS 5 #define SPI_BUS 6 +#define RPC_BUS 7 #ifdef BCMBUSTYPE @@ -77,6 +88,12 @@ #define CHIPID(chip) (chip) #endif +#ifdef BCMCHIPREV +#define CHIPREV(rev) (BCMCHIPREV) +#else +#define CHIPREV(rev) (rev) +#endif + #define DMADDR_MASK_32 0x0 #define DMADDR_MASK_30 0xc0000000 @@ -87,14 +104,73 @@ #define DMADDRWIDTH_63 63 #define DMADDRWIDTH_64 64 +#ifdef BCMDMA64OSL +typedef struct { + uint32 loaddr; + uint32 hiaddr; +} dma64addr_t; + +typedef dma64addr_t dmaaddr_t; +#define PHYSADDRHI(_pa) ((_pa).hiaddr) +#define PHYSADDRHISET(_pa, _val) \ + do { \ + (_pa).hiaddr = (_val); \ + } while (0) +#define PHYSADDRLO(_pa) ((_pa).loaddr) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa).loaddr = (_val); \ + } while (0) + +#else +typedef unsigned long dmaaddr_t; +#define PHYSADDRHI(_pa) (0) +#define PHYSADDRHISET(_pa, _val) +#define PHYSADDRLO(_pa) ((_pa)) +#define PHYSADDRLOSET(_pa, _val) \ + do { \ + (_pa) = (_val); \ + } while (0) +#endif + + +typedef struct { + dmaaddr_t addr; + uint32 length; +} hnddma_seg_t; + #define MAX_DMA_SEGS 4 -#define BCMEXTRAHDROOM 160 +typedef struct { + void *oshdmah; + uint origsize; + uint nsegs; + hnddma_seg_t segs[MAX_DMA_SEGS]; +} hnddma_seg_map_t; + + + + +#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) + +#define BCMEXTRAHDROOM 220 +#elif defined(BCM43237) && defined(BCMPKTPOOL) && defined(DMATXRC) +#define BCMEXTRAHDROOM 0 +#else +#define BCMEXTRAHDROOM 172 +#endif #define BCMDONGLEHDRSZ 12 +#define BCMDONGLEPADSZ 16 + +#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) + +#if defined(BCMASSERT_LOG) +#define BCMASSERT_SUPPORT +#endif #define BITFIELD_MASK(width) \ @@ -117,8 +193,6 @@ #define MAXSZ_NVRAM_VARS 4096 - - #define LOCATOR_EXTERN static #endif diff --git a/src/include/bcmdevs.h b/src/include/bcmdevs.h index 6604e6c..4f707c0 100644 --- a/src/include/bcmdevs.h +++ b/src/include/bcmdevs.h @@ -1,7 +1,7 @@ /* * Broadcom device-specific manifest constants. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.11.4.7 2009/05/22 06:47:57 Exp $ + * $Id: bcmdevs.h,v 13.285.2.39 2011-02-04 05:03:16 Exp $ */ @@ -37,30 +37,70 @@ #define VENDOR_JMICRON 0x197b + #define VENDOR_BROADCOM_PCMCIA 0x02d0 #define VENDOR_BROADCOM_SDIO 0x00BF -#define BCM_DNGL_VID 0xa5c -#define BCM_DNGL_BL_PID_4320 0xbd11 -#define BCM_DNGL_BL_PID_4328 0xbd12 -#define BCM_DNGL_BL_PID_4322 0xbd13 -#define BCM_DNGL_BL_PID_4325 0xbd14 -#define BCM_DNGL_BL_PID_4315 0xbd15 +#define BCM_DNGL_VID 0x0a5c +#define BCM_DNGL_BL_PID_4328 0xbd12 +#define BCM_DNGL_BL_PID_4322 0xbd13 #define BCM_DNGL_BL_PID_4319 0xbd16 -#define BCM_DNGL_BDC_PID 0xbdc - +#define BCM_DNGL_BL_PID_43236 0xbd17 +#define BCM_DNGL_BL_PID_4332 0xbd18 +#define BCM_DNGL_BL_PID_4330 0xbd19 +#define BCM_DNGL_BL_PID_43239 0xbd1b +#define BCM_DNGL_BDC_PID 0x0bdc +#define BCM_DNGL_JTAG_PID 0x4a44 #define BCM4325_D11DUAL_ID 0x431b #define BCM4325_D11G_ID 0x431c #define BCM4325_D11A_ID 0x431d +#define BCM4321_D11N_ID 0x4328 +#define BCM4321_D11N2G_ID 0x4329 +#define BCM4321_D11N5G_ID 0x432a +#define BCM4322_D11N_ID 0x432b +#define BCM4322_D11N2G_ID 0x432c +#define BCM4322_D11N5G_ID 0x432d #define BCM4329_D11N_ID 0x432e #define BCM4329_D11N2G_ID 0x432f #define BCM4329_D11N5G_ID 0x4330 #define BCM4315_D11DUAL_ID 0x4334 #define BCM4315_D11G_ID 0x4335 #define BCM4315_D11A_ID 0x4336 +#define BCM4319_D11N_ID 0x4337 +#define BCM4319_D11N2G_ID 0x4338 +#define BCM4319_D11N5G_ID 0x4339 +#define BCM43231_D11N2G_ID 0x4340 +#define BCM43221_D11N2G_ID 0x4341 +#define BCM43222_D11N_ID 0x4350 +#define BCM43222_D11N2G_ID 0x4351 +#define BCM43222_D11N5G_ID 0x4352 +#define BCM43224_D11N_ID 0x4353 +#define BCM43224_D11N_ID_VEN1 0x0576 +#define BCM43226_D11N_ID 0x4354 +#define BCM43236_D11N_ID 0x4346 +#define BCM43236_D11N2G_ID 0x4347 +#define BCM43236_D11N5G_ID 0x4348 +#define BCM43225_D11N2G_ID 0x4357 +#define BCM43421_D11N_ID 0xA99D +#define BCM4313_D11N2G_ID 0x4727 +#define BCM4330_D11N_ID 0x4360 +#define BCM4330_D11N2G_ID 0x4361 +#define BCM4330_D11N5G_ID 0x4362 +#define BCM4336_D11N_ID 0x4343 +#define BCM6362_D11N_ID 0x435f +#define BCM4331_D11N_ID 0x4331 +#define BCM4331_D11N2G_ID 0x4332 +#define BCM4331_D11N5G_ID 0x4333 +#define BCM43237_D11N_ID 0x4355 +#define BCM43237_D11N5G_ID 0x4356 +#define BCM43227_D11N2G_ID 0x4358 +#define BCM43228_D11N_ID 0x4359 +#define BCM43228_D11N5G_ID 0x435a +#define BCM43362_D11N_ID 0x4363 +#define BCM43239_D11N_ID 0x4370 #define SDIOH_FPGA_ID 0x43f2 @@ -77,16 +117,41 @@ #define BCM4306_CHIP_ID 0x4306 #define BCM4311_CHIP_ID 0x4311 +#define BCM43111_CHIP_ID 43111 +#define BCM43112_CHIP_ID 43112 #define BCM4312_CHIP_ID 0x4312 +#define BCM4313_CHIP_ID 0x4313 #define BCM4315_CHIP_ID 0x4315 #define BCM4318_CHIP_ID 0x4318 #define BCM4319_CHIP_ID 0x4319 #define BCM4320_CHIP_ID 0x4320 #define BCM4321_CHIP_ID 0x4321 #define BCM4322_CHIP_ID 0x4322 +#define BCM43221_CHIP_ID 43221 +#define BCM43222_CHIP_ID 43222 +#define BCM43224_CHIP_ID 43224 +#define BCM43225_CHIP_ID 43225 +#define BCM43227_CHIP_ID 43227 +#define BCM43228_CHIP_ID 43228 +#define BCM43226_CHIP_ID 43226 +#define BCM43231_CHIP_ID 43231 +#define BCM43234_CHIP_ID 43234 +#define BCM43235_CHIP_ID 43235 +#define BCM43236_CHIP_ID 43236 +#define BCM43237_CHIP_ID 43237 +#define BCM43238_CHIP_ID 43238 +#define BCM43239_CHIP_ID 43239 +#define BCM43420_CHIP_ID 43420 +#define BCM43421_CHIP_ID 43421 +#define BCM43428_CHIP_ID 43428 +#define BCM43431_CHIP_ID 43431 #define BCM4325_CHIP_ID 0x4325 #define BCM4328_CHIP_ID 0x4328 #define BCM4329_CHIP_ID 0x4329 +#define BCM4331_CHIP_ID 0x4331 +#define BCM4336_CHIP_ID 0x4336 +#define BCM43362_CHIP_ID 43362 +#define BCM4330_CHIP_ID 0x4330 #define BCM4402_CHIP_ID 0x4402 #define BCM4704_CHIP_ID 0x4704 #define BCM4710_CHIP_ID 0x4710 @@ -95,8 +160,7 @@ #define BCM5350_CHIP_ID 0x5350 #define BCM5352_CHIP_ID 0x5352 #define BCM5354_CHIP_ID 0x5354 -#define BCM5365_CHIP_ID 0x5365 - +#define BCM5365_CHIP_ID 0x5365 #define BCM4303_PKG_ID 2 @@ -115,5 +179,4 @@ #define HDLSIM_PKG_ID 14 #define HWSIM_PKG_ID 15 - #endif diff --git a/src/include/bcmendian.h b/src/include/bcmendian.h index 6ce70e1..04b07ec 100644 --- a/src/include/bcmendian.h +++ b/src/include/bcmendian.h @@ -1,7 +1,7 @@ /* * Byte order utilities * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: bcmendian.h,v 1.31.302.1.30.1 2009/01/13 21:40:25 Exp $ + * $Id: bcmendian.h,v 1.36 2009-11-09 05:29:43 Exp $ * * This file by default provides proper behavior on little-endian architectures. * On big-endian architectures, IL_BIGENDIAN should be defined. @@ -51,6 +51,134 @@ (((uint32)(val) & (uint32)0xffff0000U) >> 16))) +#ifndef hton16 +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define HTON32(i) BCMSWAP32(i) +#define hton32(i) bcmswap32(i) +#define NTOH16(i) BCMSWAP16(i) +#define ntoh16(i) bcmswap16(i) +#define NTOH32(i) BCMSWAP32(i) +#define ntoh32(i) bcmswap32(i) +#define LTOH16(i) (i) +#define ltoh16(i) (i) +#define LTOH32(i) (i) +#define ltoh32(i) (i) +#define HTOL16(i) (i) +#define htol16(i) (i) +#define HTOL32(i) (i) +#define htol32(i) (i) +#endif + +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) + + +#define load32_ua(a) ltoh32_ua(a) +#define store32_ua(a, v) htol32_ua_store(v, a) +#define load16_ua(a) ltoh16_ua(a) +#define store16_ua(a, v) htol16_ua_store(v, a) + +#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) +#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) +#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) +#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) + +#define ltoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#define ntoh_ua(ptr) \ + (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ + sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ + sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ + *(uint8 *)0) + +#ifdef __GNUC__ + + + +#define bcmswap16(val) ({ \ + uint16 _val = (val); \ + BCMSWAP16(_val); \ +}) + +#define bcmswap32(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32(_val); \ +}) + +#define bcmswap32by16(val) ({ \ + uint32 _val = (val); \ + BCMSWAP32BY16(_val); \ +}) + +#define bcmswap16_buf(buf, len) ({ \ + uint16 *_buf = (uint16 *)(buf); \ + uint _wds = (len) / 2; \ + while (_wds--) { \ + *_buf = bcmswap16(*_buf); \ + _buf++; \ + } \ +}) + +#define htol16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = _val >> 8; \ +}) + +#define htol32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val & 0xff; \ + _bytes[1] = (_val >> 8) & 0xff; \ + _bytes[2] = (_val >> 16) & 0xff; \ + _bytes[3] = _val >> 24; \ +}) + +#define hton16_ua_store(val, bytes) ({ \ + uint16 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 8; \ + _bytes[1] = _val & 0xff; \ +}) + +#define hton32_ua_store(val, bytes) ({ \ + uint32 _val = (val); \ + uint8 *_bytes = (uint8 *)(bytes); \ + _bytes[0] = _val >> 24; \ + _bytes[1] = (_val >> 16) & 0xff; \ + _bytes[2] = (_val >> 8) & 0xff; \ + _bytes[3] = _val & 0xff; \ +}) + +#define ltoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH16_UA(_bytes); \ +}) + +#define ltoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _LTOH32_UA(_bytes); \ +}) + +#define ntoh16_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH16_UA(_bytes); \ +}) + +#define ntoh32_ua(bytes) ({ \ + const uint8 *_bytes = (const uint8 *)(bytes); \ + _NTOH32_UA(_bytes); \ +}) + +#else + + static INLINE uint16 bcmswap16(uint16 val) { @@ -83,44 +211,6 @@ bcmswap16_buf(uint16 *buf, uint len) } } -#ifndef hton16 -#ifndef IL_BIGENDIAN -#define HTON16(i) BCMSWAP16(i) -#define HTON32(i) BCMSWAP32(i) -#define hton16(i) bcmswap16(i) -#define hton32(i) bcmswap32(i) -#define ntoh16(i) bcmswap16(i) -#define ntoh32(i) bcmswap32(i) -#define HTOL16(i) (i) -#define HTOL32(i) (i) -#define ltoh16(i) (i) -#define ltoh32(i) (i) -#define htol16(i) (i) -#define htol32(i) (i) -#else -#define HTON16(i) (i) -#define HTON32(i) (i) -#define hton16(i) (i) -#define hton32(i) (i) -#define ntoh16(i) (i) -#define ntoh32(i) (i) -#define HTOL16(i) BCMSWAP16(i) -#define HTOL32(i) BCMSWAP32(i) -#define ltoh16(i) bcmswap16(i) -#define ltoh32(i) bcmswap32(i) -#define htol16(i) bcmswap16(i) -#define htol32(i) bcmswap32(i) -#endif -#endif - -#ifndef IL_BIGENDIAN -#define ltoh16_buf(buf, i) -#define htol16_buf(buf, i) -#else -#define ltoh16_buf(buf, i) bcmswap16_buf((uint16 *)buf, i) -#define htol16_buf(buf, i) bcmswap16_buf((uint16 *)buf, i) -#endif - static INLINE void htol16_ua_store(uint16 val, uint8 *bytes) @@ -157,11 +247,6 @@ hton32_ua_store(uint32 val, uint8 *bytes) bytes[3] = val & 0xff; } -#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) -#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) -#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) -#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) - static INLINE uint16 ltoh16_ua(const void *bytes) @@ -190,16 +275,5 @@ ntoh32_ua(const void *bytes) return _NTOH32_UA((const uint8 *)bytes); } -#define ltoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)ptr : \ - sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)ptr) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)ptr) : \ - 0xfeedf00d) - -#define ntoh_ua(ptr) \ - (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)ptr : \ - sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)ptr) : \ - sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)ptr) : \ - 0xfeedf00d) - +#endif #endif diff --git a/src/include/bcmpcispi.h b/src/include/bcmpcispi.h index ca70497..fd148c5 100644 --- a/src/include/bcmpcispi.h +++ b/src/include/bcmpcispi.h @@ -1,7 +1,7 @@ /* * Broadcom PCI-SPI Host Controller Register Definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,8 +21,10 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmpcispi.h,v 13.11.8.3 2008/07/09 21:23:29 Exp $ + * $Id: bcmpcispi.h,v 13.15.112.1 2010-11-15 18:22:12 Exp $ */ +#ifndef _BCM_PCI_SPI_H +#define _BCM_PCI_SPI_H /* cpp contortions to concatenate w/arg prescan */ #ifndef PAD @@ -31,34 +33,6 @@ #define PAD _XSTR(__LINE__) #endif /* PAD */ -/* -+---------------------------------------------------------------------------+ -| | -| 7 6 5 4 3 2 1 0 | -| 0x0000 SPI_CTRL SPIE SPE 0 MSTR CPOL CPHA SPR1 SPR0 | -| 0x0004 SPI_STAT SPIF WCOL ST1 ST0 WFFUL WFEMP RFFUL RFEMP | -| 0x0008 SPI_DATA Bits 31:0, data to send out on MOSI | -| 0x000C SPI_EXT ICNT1 ICNT0 BSWAP *HSMODE ESPR1 ESPR0 | -| 0x0020 GPIO_OE 0=input, 1=output PWR_OE CS_OE | -| 0x0024 GPIO_DATA CARD:1=missing, 0=present CARD PWR_DAT CS_DAT | -| 0x0040 INT_EDGE 0=level, 1=edge DEV_E SPI_E | -| 0x0044 INT_POL 1=active high, 0=active low DEV_P SPI_P | -| 0x0048 INTMASK DEV SPI | -| 0x004C INTSTATUS DEV SPI | -| 0x0060 HEXDISP Reset value: 0x14e443f5. In hexdisp mode, value | -| shows on the Raggedstone1 4-digit 7-segment display. | -| 0x0064 CURRENT_MA Low 16 bits indicate card current consumption in mA | -| 0x006C DISP_SEL Display mode (0=hexdisp, 1=current) DSP | -| 0x00C0 PLL_CTL bit31=ext_clk, remainder unused. | -| 0x00C4 PLL_STAT LOCK | -| 0x00C8 CLK_FREQ | -| 0x00CC CLK_CNT | -| | -| *Notes: HSMODE is not implemented, never set this bit! | -| BSWAP is available in rev >= 8 | -| | -+---------------------------------------------------------------------------+ -*/ typedef volatile struct { uint32 spih_ctrl; /* 0x00 SPI Control Register */ @@ -184,16 +158,16 @@ typedef volatile struct { #define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ /* GPIO Bit definitions */ -#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ +#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ #define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ #define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ /* SPI Status Register Bit definitions */ #define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ #define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ +#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ #define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ +#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ #define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ #define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ @@ -203,3 +177,5 @@ typedef volatile struct { /* Spin bit loop bound check */ #define SPI_SPIN_BOUND 0xf4240 /* 1 million */ + +#endif /* _BCM_PCI_SPI_H */ diff --git a/src/include/bcmperf.h b/src/include/bcmperf.h index f812557..a3985cf 100644 --- a/src/include/bcmperf.h +++ b/src/include/bcmperf.h @@ -1,7 +1,7 @@ /* * Performance counters software interface. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: bcmperf.h,v 13.5 2007/09/14 22:00:59 Exp $ + * $Id: bcmperf.h,v 13.5 2007-09-14 22:00:59 Exp $ */ /* essai */ #ifndef _BCMPERF_H_ diff --git a/src/include/bcmsdbus.h b/src/include/bcmsdbus.h index ef3534e..5fda5e9 100644 --- a/src/include/bcmsdbus.h +++ b/src/include/bcmsdbus.h @@ -1,11 +1,8 @@ -#ifndef _sdio_api_h_ -#define _sdio_api_h_ - /* * Definitions for API from sdio common code (bcmsdh) to individual * host controller drivers. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,14 +22,12 @@ * 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: bcmsdbus.h,v 13.11.14.2.16.4 2009/09/30 05:11:12 Exp $ + * $Id: bcmsdbus.h,v 13.17.86.2 2010-12-23 01:13:20 Exp $ */ -/* - * The following were: - * incorrectly in bcmsdio.h - * incorrectly named using SDIOH which indicates BRCM SDIO FPGA host controller - */ +#ifndef _sdio_api_h_ +#define _sdio_api_h_ + #define SDIOH_API_RC_SUCCESS (0x00) #define SDIOH_API_RC_FAIL (0x01) @@ -79,7 +74,6 @@ extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); extern bool sdioh_interrupt_pending(sdioh_info_t *si); #endif - /* read or write one byte using cmd52 */ extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); @@ -112,6 +106,9 @@ extern int sdioh_abort(sdioh_info_t *si, uint fnc); extern int sdioh_start(sdioh_info_t *si, int stage); extern int sdioh_stop(sdioh_info_t *si); +/* Wait system lock free */ +extern int sdioh_waitlockfree(sdioh_info_t *si); + /* Reset and re-initialize the device */ extern int sdioh_sdio_reset(sdioh_info_t *si); diff --git a/src/include/bcmsdh.h b/src/include/bcmsdh.h index 4c95f5a..6131d8a 100644 --- a/src/include/bcmsdh.h +++ b/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-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -23,7 +23,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.h,v 13.35.14.7.16.5 2009/09/30 05:11:12 Exp $ + * $Id: bcmsdh.h,v 13.46.52.3 2010-10-19 00:41:44 Exp $ */ #ifndef _bcmsdh_h_ @@ -157,6 +157,9 @@ extern int bcmsdh_start(void *sdh, int stage); /* Stop SDIO Host Controller communication */ extern int bcmsdh_stop(void *sdh); +/* Wait system lock free */ +extern int bcmsdh_waitlockfree(void *sdh); + /* Returns the "Device ID" of target device on the SDIO bus. */ extern int bcmsdh_query_device(void *sdh); @@ -204,4 +207,5 @@ extern uint32 bcmsdh_cur_sbwad(void *sdh); /* Function to pass chipid and rev to lower layers for controlling pr's */ extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); + #endif /* _bcmsdh_h_ */ diff --git a/src/include/bcmsdh_sdmmc.h b/src/include/bcmsdh_sdmmc.h index f62cc21..d188c4e 100644 --- a/src/include/bcmsdh_sdmmc.h +++ b/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-2011, 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.h,v 13.1.2.2.6.3 2009/09/30 05:11:12 Exp $ + * $Id: bcmsdh_sdmmc.h,v 13.5.88.1 2010-12-23 01:13:20 Exp $ */ #ifndef __BCMSDH_SDMMC_H__ diff --git a/src/include/bcmsdpcm.h b/src/include/bcmsdpcm.h index a60727a..ee29b5c 100644 --- a/src/include/bcmsdpcm.h +++ b/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-2011, 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,22 +22,238 @@ * 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: bcmsdpcm.h,v 13.4.26.1 2009/07/06 11:56:22 Exp $ + * $Id: bcmsdpcm.h,v 13.4.90.2 2010-05-12 04:14:25 Exp $ */ #ifndef _bcmsdpcm_h_ #define _bcmsdpcm_h_ +/* + * Software allocation of To SB Mailbox resources + */ + +/* intstatus bits */ +#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ +#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ +#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ +#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ + +#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) + +/* tosbmailbox bits corresponding to intstatus bits */ +#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ +#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ +#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ +#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ +#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ + +/* tosbmailboxdata */ +#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ +#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ + +/* + * Software allocation of To Host Mailbox resources + */ + +/* intstatus bits */ +#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ +#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ +#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ +#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ + +#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) + +/* tohostmailbox bits corresponding to intstatus bits */ +#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ +#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ +#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ +#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ +#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ + +/* tohostmailboxdata */ +#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ +#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ +#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ +#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ +#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ + +#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ +#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ + +#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ +#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ + +/* + * Software-defined protocol header + */ + +/* Current protocol version */ +#define SDPCM_PROT_VERSION 4 + +/* SW frame header */ +#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ +#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ + +#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ +#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ +#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ + +#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ +#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ +#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ + +/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ +#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ +#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ +#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ +#define SDPCM_NEXTLEN_OFFSET 2 + +/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ +#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ +#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) +#define SDPCM_DOFFSET_MASK 0xff000000 +#define SDPCM_DOFFSET_SHIFT 24 + +#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ +#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) +#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ +#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) +#define SDPCM_VERSION_OFFSET 6 /* Version # */ +#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) +#define SDPCM_UNUSED_OFFSET 7 /* Spare */ +#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) + +#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ + +/* logical channel numbers */ +#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ +#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ +#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ +#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ +#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ +#define SDPCM_MAX_CHANNEL 15 + +#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ + +#define SDPCM_FLAG_RESVD0 0x01 +#define SDPCM_FLAG_RESVD1 0x02 +#define SDPCM_FLAG_GSPI_TXENAB 0x04 +#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ + +/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ +#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) + +#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) + +/* For TEST_CHANNEL packets, define another 4-byte header */ +#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); + * Semantics of Ext byte depend on command. + * Len is current or requested frame length, not + * including test header; sent little-endian. + */ +#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ +#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ +#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ +#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count */ +#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off */ + +/* Handy macro for filling in datagen packets with a pattern */ +#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) + +/* + * Software counters (first part matches hardware counters) + */ + +typedef volatile struct { + uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ + uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ + uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ + uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ + uint32 abort; /* AbortCount, SDIO: aborts */ + uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ + uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ + uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ + uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ + uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ + uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ + uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ + uint32 rxdescuflo; /* receive descriptor underflows */ + uint32 rxfifooflo; /* receive fifo overflows */ + uint32 txfifouflo; /* transmit fifo underflows */ + uint32 runt; /* runt (too short) frames recv'd from bus */ + uint32 badlen; /* frame's rxh len does not match its hw tag len */ + uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ + uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ + uint32 rxfcrc; /* frame rx header indicates crc error */ + uint32 rxfwoos; /* frame rx header indicates write out of sync */ + uint32 rxfwft; /* frame rx header indicates write frame termination */ + uint32 rxfabort; /* frame rx header indicates frame aborted */ + uint32 woosint; /* write out of sync interrupt */ + uint32 roosint; /* read out of sync interrupt */ + uint32 rftermint; /* read frame terminate interrupt */ + uint32 wftermint; /* write frame terminate interrupt */ +} sdpcmd_cnt_t; /* - * Shared structure between dongle and the host - * The structure contains pointers to trap or assert information shared with the host + * Register Access Macros + */ + +#define SDIODREV_IS(var, val) ((var) == (val)) +#define SDIODREV_GE(var, val) ((var) >= (val)) +#define SDIODREV_GT(var, val) ((var) > (val)) +#define SDIODREV_LT(var, val) ((var) < (val)) +#define SDIODREV_LE(var, val) ((var) <= (val)) + +#define SDIODDMAREG32(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) + +#define SDIODDMAREG64(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ + (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) + +#define SDIODDMAREG(h, dir, chnl) \ + (SDIODREV_LT((h)->corerev, 1) ? \ + SDIODDMAREG32((h), (dir), (chnl)) : \ + SDIODDMAREG64((h), (dir), (chnl))) + +#define PCMDDMAREG(h, dir, chnl) \ + ((dir) == DMA_TX ? \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ + (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) + +#define SDPCMDMAREG(h, dir, chnl, coreid) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODDMAREG(h, dir, chnl) : \ + PCMDDMAREG(h, dir, chnl)) + +#define SDIODFIFOREG(h, corerev) \ + (SDIODREV_LT((corerev), 1) ? \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) + +#define PCMDFIFOREG(h) \ + ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) + +#define SDPCMFIFOREG(h, coreid, corerev) \ + ((coreid) == SDIOD_CORE_ID ? \ + SDIODFIFOREG(h, corerev) : \ + PCMDFIFOREG(h)) + +/* + * Shared structure between dongle and the host. + * The structure contains pointers to trap or assert information. */ #define SDPCM_SHARED_VERSION 0x0001 #define SDPCM_SHARED_VERSION_MASK 0x00FF #define SDPCM_SHARED_ASSERT_BUILT 0x0100 #define SDPCM_SHARED_ASSERT 0x0200 #define SDPCM_SHARED_TRAP 0x0400 +#define SDPCM_SHARED_IN_BRPT 0x0800 +#define SDPCM_SHARED_SET_BRPT 0x1000 +#define SDPCM_SHARED_PENDING_BRPT 0x2000 typedef struct { uint32 flags; @@ -47,8 +263,12 @@ typedef struct { uint32 assert_line; uint32 console_addr; /* Address of hndrte_cons_t */ uint32 msgtrace_addr; + uint32 brpt_addr; } sdpcm_shared_t; extern sdpcm_shared_t sdpcm_shared; +/* Function can be used to notify host of FW halt */ +extern void sdpcmd_fwhalt(void); + #endif /* _bcmsdpcm_h_ */ diff --git a/src/include/bcmsdspi.h b/src/include/bcmsdspi.h index f65897a..0bff355 100644 --- a/src/include/bcmsdspi.h +++ b/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-2011, 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,8 +21,10 @@ * 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.h,v 13.8.10.2 2008/06/30 21:09:40 Exp $ + * $Id: bcmsdspi.h,v 13.11.86.1 2010-11-15 18:14:56 Exp $ */ +#ifndef _BCM_SD_SPI_H +#define _BCM_SD_SPI_H /* global msglevel for debug messages - bitvals come from sdiovar.h */ @@ -129,3 +131,5 @@ 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); + +#endif /* _BCM_SD_SPI_H */ diff --git a/src/include/bcmsdstd.h b/src/include/bcmsdstd.h index 5c3f61e..0f4c026 100644 --- a/src/include/bcmsdstd.h +++ b/src/include/bcmsdstd.h @@ -1,7 +1,7 @@ /* * 'Standard' SDIO HOST CONTROLLER driver * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,19 @@ * 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.3 2008/09/30 17:52:35 Exp $ + * $Id: bcmsdstd.h,v 13.21.2.6 2010-11-15 18:14:01 Exp $ */ +#ifndef _BCM_SD_STD_H +#define _BCM_SD_STD_H /* 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 +80,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 @@ -88,6 +88,8 @@ extern void sdstd_osfree(sdioh_info_t *sd); #define CLIENT_INTR 0x100 /* Get rid of this! */ +#define HC_INTR_RETUNING 0x1000 + struct sdioh_info { uint cfg_bar; /* pci cfg address for bar */ @@ -115,7 +117,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 +126,86 @@ 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 */ + int host_UHSISupported; /* whether UHSI is supported for HC. */ + int card_UHSI_voltage_Supported; /* whether UHSI is supported for + * Card in terms of Voltage [1.8 or 3.3]. + */ + int global_UHSI_Supp; /* type of UHSI support in both host and card. + * HOST_SDR_UNSUPP: capabilities not supported/matched + * HOST_SDR_12_25: SDR12 and SDR25 supported + * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd + */ + int sd3_dat_state; /* data transfer state used for retuning check */ + int sd3_tun_state; /* tuning state used for retuning check */ + bool sd3_tuning_reqd; /* tuning requirement parameter */ + uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ }; +#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 */ + +/* States for Tuning and corr data */ +#define TUNING_IDLE 0 +#define TUNING_START 1 +#define TUNING_START_AFTER_DAT 2 +#define TUNING_ONGOING 3 + +#define DATA_TRANSFER_IDLE 0 +#define DATA_TRANSFER_ONGOING 1 + +/* 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 */ @@ -173,6 +243,25 @@ extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); /* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ extern void sdstd_lock(sdioh_info_t *sd); extern void sdstd_unlock(sdioh_info_t *sd); +extern void sdstd_waitlockfree(sdioh_info_t *sd); /* OS-specific wait-for-interrupt-or-status */ -extern uint16 sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield); +extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); + +/* used by bcmsdstd_linux [implemented in sdstd] */ +extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); +extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); +extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); +extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); +extern int sdstd_3_get_tune_state(sdioh_info_t *sd); +extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); +extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); +extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); +extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); + +/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ +extern void sdstd_3_start_tuning(sdioh_info_t *sd); +extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); +extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); + +#endif /* _BCM_SD_STD_H */ diff --git a/src/include/bcmspi.h b/src/include/bcmspi.h index 5423e03..0eb2a30 100644 --- a/src/include/bcmspi.h +++ b/src/include/bcmspi.h @@ -1,7 +1,7 @@ /* * Broadcom SPI Low-Level Hardware Driver API * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,8 +21,10 @@ * 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: bcmspi.h,v 13.3.10.2 2008/06/30 21:09:40 Exp $ + * $Id: bcmspi.h,v 13.5.112.1 2010-11-15 18:13:09 Exp $ */ +#ifndef _BCM_SPI_H +#define _BCM_SPI_H extern void spi_devintr_off(sdioh_info_t *sd); extern void spi_devintr_on(sdioh_info_t *sd); @@ -34,3 +36,5 @@ extern bool spi_hw_detach(sdioh_info_t *sd); extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); extern void spi_spinbits(sdioh_info_t *sd); extern void spi_waitbits(sdioh_info_t *sd, bool yield); + +#endif /* _BCM_SPI_H */ diff --git a/src/include/bcmutils.h b/src/include/bcmutils.h index 1ac2a7a..f7f2300 100644 --- a/src/include/bcmutils.h +++ b/src/include/bcmutils.h @@ -1,7 +1,7 @@ /* * Misc useful os-independent macros and functions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,13 +20,22 @@ * 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.26.5 2009/07/15 21:13:22 Exp $ + * + * $Id: bcmutils.h,v 13.236.2.16 2011-01-26 00:45:06 Exp $ */ #ifndef _bcmutils_h_ #define _bcmutils_h_ +#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) +#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) +#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) + +#ifdef __cplusplus +extern "C" { +#endif + #define _BCM_U 0x01 #define _BCM_L 0x02 @@ -79,7 +88,6 @@ struct bcmstrbuf { } - #ifndef PKTQ_LEN_DEFAULT #define PKTQ_LEN_DEFAULT 128 #endif @@ -118,9 +126,121 @@ struct spktq { #define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) +typedef bool (*ifpkt_cb_t)(void*, int); + +#ifdef BCMPKTPOOL +#define POOL_ENAB(pool) ((pool) && (pool)->inited) +#if defined(BCM4329C0) +#define SHARED_POOL (pktpool_shared_ptr) +#else +#define SHARED_POOL (pktpool_shared) +#endif +#else +#define POOL_ENAB(bus) 0 +#define SHARED_POOL ((struct pktpool *)NULL) +#endif + +#define PKTPOOL_LEN_MAX 40 +#define PKTPOOL_CB_MAX 3 + +struct pktpool; +typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); +typedef struct { + pktpool_cb_t cb; + void *arg; +} pktpool_cbinfo_t; + +#ifdef BCMDBG_POOL + +#define POOL_IDLE 0 +#define POOL_RXFILL 1 +#define POOL_RXDH 2 +#define POOL_RXD11 3 +#define POOL_TXDH 4 +#define POOL_TXD11 5 +#define POOL_AMPDU 6 +#define POOL_TXENQ 7 + +typedef struct { + void *p; + uint32 cycles; + uint32 dur; +} pktpool_dbg_t; + +typedef struct { + uint8 txdh; + uint8 txd11; + uint8 enq; + uint8 rxdh; + uint8 rxd11; + uint8 rxfill; + uint8 idle; +} pktpool_stats_t; +#endif + +typedef struct pktpool { + bool inited; + uint16 r; + uint16 w; + uint16 len; + uint16 maxlen; + uint16 plen; + bool istx; + bool empty; + uint8 cbtoggle; + uint8 cbcnt; + uint8 ecbcnt; + bool emptycb_disable; + pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; + pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; + void *q[PKTPOOL_LEN_MAX + 1]; + +#ifdef BCMDBG_POOL + uint8 dbg_cbcnt; + pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; + uint16 dbg_qlen; + pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; +#endif +} pktpool_t; + +#if defined(BCM4329C0) +extern pktpool_t *pktpool_shared_ptr; +#else +extern pktpool_t *pktpool_shared; +#endif + +extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); +extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); +extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); +extern void* pktpool_get(pktpool_t *pktp); +extern void pktpool_free(pktpool_t *pktp, void *p); +extern int pktpool_add(pktpool_t *pktp, void *p); +extern uint16 pktpool_avail(pktpool_t *pktp); +extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); + +#define POOLPTR(pp) ((pktpool_t *)(pp)) +#define pktpool_len(pp) (POOLPTR(pp)->len - 1) +#define pktpool_plen(pp) (POOLPTR(pp)->plen) +#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) + +#ifdef BCMDBG_POOL +extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); +extern int pktpool_start_trigger(pktpool_t *pktp, void *p); +extern int pktpool_dbg_dump(pktpool_t *pktp); +extern int pktpool_dbg_notify(pktpool_t *pktp); +extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); +#endif + + struct ether_addr; +extern int ether_isbcast(const void *ea); +extern int ether_isnulladdr(const void *ea); + #define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) @@ -137,12 +257,10 @@ extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); extern void *pktq_pdeq(struct pktq *pq, int prec); extern void *pktq_pdeq_tail(struct pktq *pq, int prec); -extern bool pktq_pdel(struct pktq *pq, void *p, int prec); - +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg); -extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); - -extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); @@ -170,6 +288,7 @@ extern void *pktq_deq(struct pktq *pq, int *prec_out); extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); extern void *pktq_peek(struct pktq *pq, int *prec_out); extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); @@ -211,6 +330,8 @@ extern void bcm_mdelay(uint ms); extern char *getvar(char *vars, const char *name); extern int getintvar(char *vars, const char *name); +extern int getintvararray(char *vars, const char *name, int index); +extern int getintvararraysize(char *vars, const char *name); extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); #define bcm_perf_enable() #define bcmstats(fmt) @@ -222,6 +343,9 @@ extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); #define bcmprinttslogs() #define bcmprinttstamp(us) +extern char *bcm_nvram_vars(uint *length); +extern int bcm_nvram_cache(void *sih); + @@ -243,12 +367,16 @@ typedef struct bcm_iovar { #define IOV_GVAL(id) ((id)*2) #define IOV_SVAL(id) (((id)*2)+IOV_SET) #define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) +#define IOV_ID(actionid) (actionid >> 1) extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); - +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); +#endif #endif @@ -330,8 +458,13 @@ 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_LAST BCME_VERSION +#define BCME_VERSION -37 +#define BCME_TXFAIL -38 +#define BCME_RXFAIL -39 +#define BCME_NODEVICE -40 +#define BCME_NMODE_DISABLED -41 +#define BCME_NONRESIDENT -42 +#define BCME_LAST BCME_NONRESIDENT #define BCMERRSTRINGTABLE { \ @@ -372,7 +505,12 @@ 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" \ + "Incorrect version", \ + "TX Failure", \ + "RX Failure", \ + "Device Not Present", \ + "NMODE Disabled", \ + "Nonresident overlay access", \ } #ifndef ABS @@ -389,7 +527,7 @@ extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool #define CEIL(x, y) (((x) + ((y)-1)) / (y)) #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) -#define ISALIGNED(a, x) (((a) & ((x)-1)) == 0) +#define ISALIGNED(a, x) (((uintptr)(a) & ((x)-1)) == 0) #define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ & ~((boundary) - 1)) #define ISPOWEROF2(x) ((((x)-1)&(x)) == 0) @@ -402,6 +540,10 @@ extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool #endif +extern void *_bcmutils_dummy_fn; +#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) + + #ifndef setbit #ifndef NBBY #define NBBY 8 @@ -467,68 +609,6 @@ typedef struct bcm_tlv { #define ETHER_ADDR_STR_LEN 18 -#ifdef IL_BIGENDIAN -static INLINE uint32 -load32_ua(uint8 *a) -{ - return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]); -} - -static INLINE void -store32_ua(uint8 *a, uint32 v) -{ - a[0] = (v >> 24) & 0xff; - a[1] = (v >> 16) & 0xff; - a[2] = (v >> 8) & 0xff; - a[3] = v & 0xff; -} - -static INLINE uint16 -load16_ua(uint8 *a) -{ - return ((a[0] << 8) | a[1]); -} - -static INLINE void -store16_ua(uint8 *a, uint16 v) -{ - a[0] = (v >> 8) & 0xff; - a[1] = v & 0xff; -} - -#else - -static INLINE uint32 -load32_ua(uint8 *a) -{ - return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]); -} - -static INLINE void -store32_ua(uint8 *a, uint32 v) -{ - a[3] = (v >> 24) & 0xff; - a[2] = (v >> 16) & 0xff; - a[1] = (v >> 8) & 0xff; - a[0] = v & 0xff; -} - -static INLINE uint16 -load16_ua(uint8 *a) -{ - return ((a[1] << 8) | a[0]); -} - -static INLINE void -store16_ua(uint8 *a, uint16 v) -{ - a[1] = (v >> 8) & 0xff; - a[0] = v & 0xff; -} - -#endif - - static INLINE void xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) @@ -561,11 +641,18 @@ extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); #if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ defined(WLMSG_ASSOC) extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); +#endif + +#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ + defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) extern int bcm_format_hex(char *str, const void *bytes, int len); -#endif -extern void prhex(const char *msg, uchar *buf, uint len); +#endif + +extern const char *bcm_crypto_algo_name(uint algo); +extern char *bcm_chipname(uint chipid, char *buf, uint len); extern char *bcm_brev_str(uint32 brev, char *buf); extern void printbig(char *buf); +extern void prhex(const char *msg, uchar *buf, uint len); extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); @@ -607,4 +694,13 @@ extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint le extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); + +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +unsigned int process_nvram_vars(char *varbuf, unsigned int len); + +#ifdef __cplusplus + } +#endif + #endif diff --git a/src/include/bcmwifi.h b/src/include/bcmwifi.h index afb7f08..45f3c03 100644 --- a/src/include/bcmwifi.h +++ b/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-2011, 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,8 @@ * 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.44.2 2009/07/15 21:13:22 Exp $ + * + * $Id: bcmwifi.h,v 1.29.6.3 2010-08-03 17:47:04 Exp $ */ @@ -71,40 +72,55 @@ typedef uint16 chanspec_t; #define WF_CHAN_FACTOR_4_G 8000 -#define LOWER_20_SB(channel) ((channel > CH_10MHZ_APART) ? (channel - CH_10MHZ_APART) : 0) -#define UPPER_20_SB(channel) ((channel < (MAXCHANNEL - CH_10MHZ_APART)) ? \ - (channel + CH_10MHZ_APART) : 0) +#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) +#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ + ((channel) + CH_10MHZ_APART) : 0) #define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) #define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define NEXT_20MHZ_CHAN(channel) ((channel < (MAXCHANNEL - CH_20MHZ_APART)) ? \ - (channel + CH_20MHZ_APART) : 0) +#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ + ((channel) + CH_20MHZ_APART) : 0) #define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ WL_CHANSPEC_BAND_5G)) -#define CHSPEC_CHANNEL(chspec) ((uint8)(chspec & WL_CHANSPEC_CHAN_MASK)) -#define CHSPEC_CTL_SB(chspec) (chspec & WL_CHANSPEC_CTL_SB_MASK) -#define CHSPEC_BW(chspec) (chspec & WL_CHANSPEC_BW_MASK) -#define CHSPEC_BAND(chspec) (chspec & WL_CHANSPEC_BAND_MASK) +#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) + + +#define CHSPEC_CTL_SB(chspec) (chspec & WL_CHANSPEC_CTL_SB_MASK) +#define CHSPEC_BW(chspec) (chspec & WL_CHANSPEC_BW_MASK) -#define CHSPEC_IS10(chspec) ((chspec & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -#define CHSPEC_IS20(chspec) ((chspec & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) +#ifdef WL11N_20MHZONLY +#define CHSPEC_IS10(chspec) 0 +#define CHSPEC_IS20(chspec) 1 +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) 0 +#endif + +#else + +#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) +#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) #ifndef CHSPEC_IS40 #define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) #endif -#define CHSPEC_IS5G(chspec) ((chspec & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) -#define CHSPEC_IS2G(chspec) ((chspec & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) -#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 CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G((chspec))? WLC_BAND_5G: WLC_BAND_2G) +#endif + +#define CHSPEC_IS20_UNCOND(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) + +#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) +#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) +#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)))) + (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/src/include/dhdioctl.h b/src/include/dhdioctl.h index dbdbb47..abe4efb 100644 --- a/src/include/dhdioctl.h +++ b/src/include/dhdioctl.h @@ -5,7 +5,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -25,7 +25,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: dhdioctl.h,v 13.7.8.1.4.1.30.2 2008/11/13 17:33:39 Exp $ + * $Id: dhdioctl.h,v 13.11.10.1 2010-12-22 23:47:26 Exp $ */ #ifndef _dhdioctl_h_ @@ -50,6 +50,12 @@ typedef struct dhd_ioctl { uint driver; /* to identify target driver */ } dhd_ioctl_t; +/* Underlying BUS definition */ +enum { + BUS_TYPE_USB = 0, /* for USB dongles */ + BUS_TYPE_SDIO /* for SDIO dongles */ +}; + /* per-driver magic numbers */ #define DHD_IOCTL_MAGIC 0x00444944 @@ -79,6 +85,7 @@ typedef struct dhd_ioctl { #define DHD_GLOM_VAL 0x0400 #define DHD_EVENT_VAL 0x0800 #define DHD_BTA_VAL 0x1000 +#define DHD_ISCAN_VAL 0x2000 #ifdef SDTEST /* For pktgen iovar */ diff --git a/src/include/epivers.h b/src/include/epivers.h index f72c0cd..1b8a3e8 100644 --- a/src/include/epivers.h +++ b/src/include/epivers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -19,7 +19,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: epivers.h.in,v 13.25 2005/10/28 18:35:33 Exp $ + * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 Exp $ * */ @@ -27,22 +27,23 @@ #ifndef _epivers_h_ #define _epivers_h_ -#define EPI_MAJOR_VERSION 4 +#define EPI_MAJOR_VERSION 5 -#define EPI_MINOR_VERSION 217 +#define EPI_MINOR_VERSION 90 -#define EPI_RC_NUMBER 58 +#define EPI_RC_NUMBER 125 -#define EPI_INCREMENTAL_NUMBER 0 +#define EPI_INCREMENTAL_NUMBER 14 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 217, 58, 0 +#define EPI_VERSION 5, 90, 125, 14 -#define EPI_VERSION_NUM 0x04d93a00 +#define EPI_VERSION_NUM 0x055a7d0e +#define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "4.217.58.0" -#define EPI_ROUTER_VERSION_STR "4.217.58.0" + +#define EPI_VERSION_STR "5.90.125.14" #endif diff --git a/src/include/hndpmu.h b/src/include/hndpmu.h index 32eea40..51c51b9 100644 --- a/src/include/hndpmu.h +++ b/src/include/hndpmu.h @@ -1,7 +1,7 @@ /* * HND SiliconBackplane PMU support. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: hndpmu.h,v 13.14.4.3.4.3.22.2 2009/01/21 23:54:44 Exp $ + * $Id: hndpmu.h,v 13.35.8.5 2011-02-11 00:56:32 Exp $ */ #ifndef _hndpmu_h_ diff --git a/src/include/hndrte_armtrap.h b/src/include/hndrte_armtrap.h new file mode 100644 index 0000000..8b9615c --- /dev/null +++ b/src/include/hndrte_armtrap.h @@ -0,0 +1,88 @@ +/* + * HNDRTE arm trap handling. + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: hndrte_armtrap.h,v 13.4.14.1 2011-02-05 00:04:30 Exp $ + */ + +#ifndef _hndrte_armtrap_h +#define _hndrte_armtrap_h + + +/* ARM trap handling */ + +/* Trap types defined by ARM (see arminc.h) */ + +/* Trap locations in lo memory */ +#define TRAP_STRIDE 4 +#define FIRST_TRAP TR_RST +#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) + +#if defined(__ARM_ARCH_4T__) +#define MAX_TRAP_TYPE (TR_FIQ + 1) +#elif defined(__ARM_ARCH_7M__) +#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) +#endif /* __ARM_ARCH_7M__ */ + +/* The trap structure is defined here as offsets for assembly */ +#define TR_TYPE 0x00 +#define TR_EPC 0x04 +#define TR_CPSR 0x08 +#define TR_SPSR 0x0c +#define TR_REGS 0x10 +#define TR_REG(n) (TR_REGS + (n) * 4) +#define TR_SP TR_REG(13) +#define TR_LR TR_REG(14) +#define TR_PC TR_REG(15) + +#define TRAP_T_SIZE 80 + +#ifndef _LANGUAGE_ASSEMBLY + +#include <typedefs.h> + +typedef struct _trap_struct { + uint32 type; + uint32 epc; + uint32 cpsr; + uint32 spsr; + uint32 r0; + uint32 r1; + uint32 r2; + uint32 r3; + uint32 r4; + uint32 r5; + uint32 r6; + uint32 r7; + uint32 r8; + uint32 r9; + uint32 r10; + uint32 r11; + uint32 r12; + uint32 r13; + uint32 r14; + uint32 pc; +} trap_t; + +#endif /* !_LANGUAGE_ASSEMBLY */ + +#endif /* _hndrte_armtrap_h */ diff --git a/src/include/hndrte_cons.h b/src/include/hndrte_cons.h new file mode 100644 index 0000000..b9ede53 --- /dev/null +++ b/src/include/hndrte_cons.h @@ -0,0 +1,68 @@ +/* + * Console support for hndrte. + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: hndrte_cons.h,v 13.4.10.4 2011-02-05 00:08:20 Exp $ + */ + +#ifndef _HNDRTE_CONS_H +#define _HNDRTE_CONS_H + +#include <typedefs.h> + +#define CBUF_LEN (128) + +#define LOG_BUF_LEN 1024 + +typedef struct { + uint32 buf; /* Can't be pointer on (64-bit) hosts */ + uint buf_size; + uint idx; + char *_buf_compat; /* redundant pointer for backward compat. */ +} hndrte_log_t; + +typedef struct { + /* Virtual UART + * When there is no UART (e.g. Quickturn), the host should write a complete + * input line directly into cbuf and then write the length into vcons_in. + * This may also be used when there is a real UART (at risk of conflicting with + * the real UART). vcons_out is currently unused. + */ + volatile uint vcons_in; + volatile uint vcons_out; + + /* Output (logging) buffer + * Console output is written to a ring buffer log_buf at index log_idx. + * The host may read the output when it sees log_idx advance. + * Output will be lost if the output wraps around faster than the host polls. + */ + hndrte_log_t log; + + /* Console input line buffer + * Characters are read one at a time into cbuf until <CR> is received, then + * the buffer is processed as a command line. Also used for virtual UART. + */ + uint cbuf_idx; + char cbuf[CBUF_LEN]; +} hndrte_cons_t; + +#endif /* _HNDRTE_CONS_H */ diff --git a/src/include/hndsoc.h b/src/include/hndsoc.h index a3dca3a..4e26121 100644 --- a/src/include/hndsoc.h +++ b/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-2011, 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: hndsoc.h,v 13.3.10.3 2008/08/06 03:43:25 Exp $ + * $Id: hndsoc.h,v 13.11 2009-12-03 23:52:31 Exp $ */ #ifndef _HNDSOC_H @@ -40,17 +40,19 @@ #define SI_PCI_MEM_SZ (64 * 1024 * 1024) #define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ #define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ +#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ #define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ + +#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ #define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ -#ifndef SI_MAXCORES #define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software * convenience and could be changed if we * make any larger chips */ -#endif #define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ +#define SI_FASTRAM_SWAPPED 0x19800000 #define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ #define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ @@ -118,7 +120,7 @@ #define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ #define SDIOD_CORE_ID 0x829 /* SDIO device core */ #define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ -#define QNPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ +#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ #define MIPS74K_CORE_ID 0x82c /* mips 74k core */ #define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ #define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ @@ -128,6 +130,8 @@ #define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ #define SPIH_CORE_ID 0x833 /* SPI host core */ #define I2S_CORE_ID 0x834 /* I2S core */ +#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ +#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ #define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ #define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all * unused address ranges @@ -141,6 +145,7 @@ /* SOC Interconnect types (aka chip types) */ #define SOCI_SB 0 #define SOCI_AI 1 +#define SOCI_UBUS 2 /* Common core control flags */ #define SICF_BIST_EN 0x8000 @@ -168,8 +173,15 @@ #define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ #define CCS_HTAREQ 0x00000010 /* HT Avail Request */ #define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ +#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ +#define CCS_ERSRC_REQ_SHIFT 8 #define CCS_ALPAVAIL 0x00010000 /* ALP is available */ #define CCS_HTAVAIL 0x00020000 /* HT is available */ +#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */ +#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ +#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ +#define CCS_ERSRC_STS_SHIFT 24 + #define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ #define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ @@ -190,6 +202,6 @@ #define BISZ_DATAEND_IDX 4 /* 4: data end */ #define BISZ_BSSST_IDX 5 /* 5: bss start */ #define BISZ_BSSEND_IDX 6 /* 6: bss end */ -#define BISZ_SIZE 7 /* descriptor size in 32-bit intergers */ +#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ #endif /* _HNDSOC_H */ diff --git a/src/include/htsf.h b/src/include/htsf.h new file mode 100644 index 0000000..379fbbe --- /dev/null +++ b/src/include/htsf.h @@ -0,0 +1,74 @@ +/* + * Time stamps for latency measurements + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: htsf.h,v 1.1.2.4 2011-01-21 08:27:03 Exp $ + */ +#ifndef _HTSF_H_ +#define _HTSF_H_ + +#define HTSFMAGIC 0xCDCDABAB /* in network order for tcpdump */ +#define HTSFENDMAGIC 0xEFEFABAB /* to distinguish from RT2 magic */ +#define HTSF_HOSTOFFSET 102 +#define HTSF_DNGLOFFSET HTSF_HOSTOFFSET - 4 +#define HTSF_DNGLOFFSET2 HTSF_HOSTOFFSET + 106 +#define HTSF_MIN_PKTLEN 200 +#define ETHER_TYPE_BRCM_PKTDLYSTATS 0x886d + +typedef enum htsfts_type { + T10, + T20, + T30, + T40, + T50, + T60, + T70, + T80, + T90, + TA0, + TE0 +} htsf_timestamp_t; + +typedef struct { + uint32 magic; + uint32 prio; + uint32 seqnum; + uint32 misc; + uint32 c10; + uint32 t10; + uint32 c20; + uint32 t20; + uint32 t30; + uint32 t40; + uint32 t50; + uint32 t60; + uint32 t70; + uint32 t80; + uint32 t90; + uint32 cA0; + uint32 tA0; + uint32 cE0; + uint32 tE0; + uint32 endmagic; +} htsfts_t; + +#endif /* _HTSF_H_ */ diff --git a/src/include/linux_osl.h b/src/include/linux_osl.h index 4ddc09c..1ec136e 100644 --- a/src/include/linux_osl.h +++ b/src/include/linux_osl.h @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.h,v 13.131.44.1 2008/12/02 21:02:37 Exp $ + * $Id: linux_osl.h,v 13.158.6.3 2010-12-22 23:47:26 Exp $ */ @@ -31,25 +31,42 @@ #include <typedefs.h> -#include <linuxver.h> +extern void * osl_os_open_image(char * filename); +extern int osl_os_get_image_block(char * buf, int len, void * image); +extern void osl_os_close_image(void * image); -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#if GCC_VERSION > 30100 -#define ASSERT(exp) do {} while (0) -#else +#ifdef BCMDRIVER -#define ASSERT(exp) -#endif + +extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); +extern void osl_detach(osl_t *osh); + + +extern uint32 g_assert_type; + + +#if defined(BCMASSERT_LOG) + #define ASSERT(exp) \ + do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) +extern void osl_assert(char *exp, char *file, int line); +#else + #ifdef __GNUC__ + #define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) + #if GCC_VERSION > 30100 + #define ASSERT(exp) do {} while (0) + #else + + #define ASSERT(exp) + #endif + #endif #endif #define OSL_DELAY(usec) osl_delay(usec) extern void osl_delay(uint usec); - - #define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) #define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ @@ -80,39 +97,37 @@ typedef struct { void *tx_ctx; } osl_pubinfo_t; - -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); -extern void osl_detach(osl_t *osh); - -#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ - do { \ - ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ - ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ +#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ + do { \ + ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ + ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ } while (0) -#define BUS_SWAP32(v) (v) +#define BUS_SWAP32(v) (v) -#define MALLOC(osh, size) osl_malloc((osh), (size)) -#define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) -#define MALLOCED(osh) osl_malloced((osh)) + #define MALLOC(osh, size) osl_malloc((osh), (size)) + #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) + #define MALLOCED(osh) osl_malloced((osh)) + extern void *osl_malloc(osl_t *osh, uint size); + extern void osl_mfree(osl_t *osh, void *addr, uint size); + extern uint osl_malloced(osl_t *osh); +#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC) +#define NATIVE_MFREE(osh, addr, size) kfree(addr) #define MALLOC_FAILED(osh) osl_malloc_failed((osh)) - -extern void *osl_malloc(osl_t *osh, uint size); -extern void osl_mfree(osl_t *osh, void *addr, uint size); -extern uint osl_malloced(osl_t *osh); extern uint osl_malloc_failed(osl_t *osh); -#define DMA_CONSISTENT_ALIGN PAGE_SIZE -#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (pap)) +#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() +#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) #define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) -extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap); +extern uint osl_dma_consistent_align(void); +extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap); extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); @@ -131,70 +146,77 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) -#include <bcmsdh.h> -#define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v))) -#define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r)))) + #include <bcmsdh.h> + #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v))) + #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r)))) + + #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ + mmap_op else bus_op + #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ + mmap_op : bus_op + +#define OSL_ERROR(bcmerror) osl_error(bcmerror) +extern int osl_error(int bcmerror); -#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ - mmap_op else bus_op -#define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ - mmap_op : bus_op +#define PKTBUFSZ 2048 -#ifndef printf -#define printf(fmt, args...) printk(fmt, ## args) -#endif -#include <linux/kernel.h> -#include <linux/string.h> +#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) +#define printf(fmt, args...) printk(fmt , ## args) +#include <linux/kernel.h> +#include <linux/string.h> + +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) +#define bzero(b, len) memset((b), '\0', (len)) -#ifndef IL_BIGENDIAN + +#ifndef __mips__ #define R_REG(osh, r) (\ SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \ sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \ readl((volatile uint32*)(r)), OSL_READ_REG(osh, r)) \ ) -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ - case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ - case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#else +#else #define R_REG(osh, r) (\ SELECT_BUS_READ(osh, \ ({ \ __typeof(*(r)) __osl_v; \ + __asm__ __volatile__("sync"); \ switch (sizeof(*(r))) { \ case sizeof(uint8): __osl_v = \ - readb((volatile uint8*)((uintptr)(r)^3)); break; \ + readb((volatile uint8*)(r)); break; \ case sizeof(uint16): __osl_v = \ - readw((volatile uint16*)((uintptr)(r)^2)); break; \ + readw((volatile uint16*)(r)); break; \ case sizeof(uint32): __osl_v = \ readl((volatile uint32*)(r)); break; \ } \ + __asm__ __volatile__("sync"); \ __osl_v; \ }), \ - OSL_READ_REG(osh, r)) \ + ({ \ + __typeof(*(r)) __osl_v; \ + __asm__ __volatile__("sync"); \ + __osl_v = OSL_READ_REG(osh, r); \ + __asm__ __volatile__("sync"); \ + __osl_v; \ + })) \ ) +#endif + #define W_REG(osh, r, v) do { \ SELECT_BUS_WRITE(osh, \ switch (sizeof(*(r))) { \ - case sizeof(uint8): writeb((uint8)(v), \ - (volatile uint8*)((uintptr)(r)^3)); break; \ - case sizeof(uint16): writew((uint16)(v), \ - (volatile uint16*)((uintptr)(r)^2)); break; \ - case sizeof(uint32): writel((uint32)(v), \ - (volatile uint32*)(r)); break; \ + case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ + case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ + case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ }, \ (OSL_WRITE_REG(osh, r, v))); \ } while (0) -#endif + #define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) @@ -205,7 +227,14 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define bzero(b, len) memset((b), '\0', (len)) -#define OSL_UNCACHED(va) ((void*)va) +#ifdef __mips__ +#include <asm/addrspace.h> +#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va))) +#define OSL_CACHED(va) ((void *)KSEG0ADDR((va))) +#else +#define OSL_UNCACHED(va) ((void *)va) +#define OSL_CACHED(va) ((void *)va) +#endif #if defined(__i386__) @@ -221,7 +250,7 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #if !defined(CONFIG_MMC_MSM7X00A) #define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) #else -#define REG_MAP(pa, size) (void *)(0) +#define REG_MAP(pa, size) (void *)(0) #endif #define REG_UNMAP(va) iounmap((va)) @@ -231,8 +260,18 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define BZERO_SM(r, len) memset((r), '\0', (len)) +#include <linuxver.h> + + #define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#define PKTLIST_DUMP(osh, buf) +#define PKTDBG_TRACE(osh, pkt, bit) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) +#ifdef DHD_USE_STATIC_BUF +#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) +#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) +#endif #define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) #define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) #define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) @@ -242,31 +281,97 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) #define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) #define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) -#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) #define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) #define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced -#define PKTLIST_DUMP(osh, buf) +#define PKTSETPOOL(osh, skb, x, y) do {} while (0) +#define PKTPOOL(osh, skb) FALSE +#define PKTSHRINK(osh, m) (m) + +#ifdef CTFPOOL +#define CTFPOOL_REFILL_THRESH 3 +typedef struct ctfpool { + void *head; + spinlock_t lock; + uint max_obj; + uint curr_obj; + uint obj_size; + uint refills; + uint fast_allocs; + uint fast_frees; + uint slow_allocs; +} ctfpool_t; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define FASTBUF (1 << 4) +#define CTFBUF (1 << 5) +#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF) +#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)) +#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF) +#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF)) +#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF) +#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) +#else +#define FASTBUF (1 << 0) +#define CTFBUF (1 << 1) +#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF) +#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)) +#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF) +#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF)) +#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF) +#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF) +#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) +#endif + +#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) +#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) + +extern void *osl_ctfpool_add(osl_t *osh); +extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); +extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); +extern void osl_ctfpool_cleanup(osl_t *osh); +extern void osl_ctfpool_stats(osl_t *osh, void *b); +#endif + +#ifdef HNDCTF +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#define SKIPCT (1 << 6) +#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT) +#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)) +#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT) +#else +#define SKIPCT (1 << 2) +#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT) +#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)) +#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT) +#endif +#else +#define PKTSETSKIPCT(osh, skb) +#define PKTCLRSKIPCT(osh, skb) +#define PKTSKIPCT(osh, skb) +#endif -extern void *osl_pktget(osl_t *osh, uint len); extern void osl_pktfree(osl_t *osh, void *skb, bool send); -extern void *osl_pktdup(osl_t *osh, void *skb); +extern void *osl_pktget_static(osl_t *osh, uint len); +extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); +extern void *osl_pktget(osl_t *osh, uint len); +extern void *osl_pktdup(osl_t *osh, void *skb); static INLINE void * -osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb) +osl_pkt_frmnative(osl_pubinfo_t *osh, void *pkt) { struct sk_buff *nskb; if (osh->pkttag) - bzero((void*)skb->cb, OSL_PKTTAG_SZ); + bzero((void*)((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ); - for (nskb = skb; nskb; nskb = nskb->next) { + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { osh->pktalloced++; } - return (void *)skb; + return (void *)pkt; } #define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb)) @@ -299,13 +404,28 @@ osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt) #define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) -#define OSL_ERROR(bcmerror) osl_error(bcmerror) -extern int osl_error(int bcmerror); +#else -#define PKTBUFSZ 2048 -#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) + #define ASSERT(exp) do {} while (0) + + +#define MALLOC(o, l) malloc(l) +#define MFREE(o, p, l) free(p) +#include <stdlib.h> + + +#include <string.h> + + +#include <stdio.h> + + +extern void bcopy(const void *src, void *dst, size_t len); +extern int bcmp(const void *b1, const void *b2, size_t len); +extern void bzero(void *b, size_t len); +#endif #endif diff --git a/src/include/linuxver.h b/src/include/linuxver.h index f515b35..ddcf8df 100644 --- a/src/include/linuxver.h +++ b/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-2011, 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.22.3 2009/06/18 00:42:34 Exp $ + * $Id: linuxver.h,v 13.53.2.2 2010-12-22 23:47:26 Exp $ */ @@ -33,8 +33,12 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #include <linux/config.h> #else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#include <generated/autoconf.h> +#else #include <linux/autoconf.h> #endif +#endif #include <linux/module.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) @@ -90,9 +94,9 @@ #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -#define MY_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func) +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) #else -#define MY_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func, _data) +#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) typedef void (*work_func_t)(void *work); #endif @@ -121,9 +125,25 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) #ifndef SANDGATE2G #define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT #endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) +#include <linux/sched.h> +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#include <net/lib80211.h> +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) +#include <linux/ieee80211.h> +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) +#include <net/ieee80211.h> +#endif +#endif + #ifndef __exit #define __exit @@ -190,6 +210,18 @@ extern void pci_unregister_driver(struct pci_driver *drv); #endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) +#define WL_USE_NETDEV_OPS +#else +#undef WL_USE_NETDEV_OPS +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL_INPUT) +#define WL_CONFIG_RFKILL_INPUT +#else +#undef WL_CONFIG_RFKILL_INPUT +#endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) @@ -335,10 +367,16 @@ static inline void tasklet_init(struct tasklet_struct *tasklet, #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) - +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) +#define PCI_SAVE_STATE(a, b) pci_save_state(a) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) +#else +#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) +#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) static inline int pci_save_state(struct pci_dev *dev, u32 *buffer) { @@ -369,7 +407,6 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) } return 0; } - #endif @@ -425,7 +462,68 @@ pci_restore_state(struct pci_dev *dev, u32 *buffer) #define CHECKSUM_HW CHECKSUM_PARTIAL #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +typedef struct { + void *parent; + struct task_struct *p_task; + long thr_pid; + int prio; + struct semaphore sema; + bool terminated; + struct completion completed; +} tsk_ctl_t; + + + + +#ifdef DHD_DEBUG +#define DBG_THR(x) printk x +#else +#define DBG_THR(x) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) +#else +#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) +#endif + + +#define PROC_START(thread_func, owner, tsk_ctl, flags) \ +{ \ + sema_init(&((tsk_ctl)->sema), 0); \ + init_completion(&((tsk_ctl)->completed)); \ + (tsk_ctl)->parent = owner; \ + (tsk_ctl)->terminated = FALSE; \ + (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ + if ((tsk_ctl)->thr_pid > 0) \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ +} + +#define PROC_STOP(tsk_ctl) \ +{ \ + (tsk_ctl)->terminated = TRUE; \ + smp_wmb(); \ + up(&((tsk_ctl)->sema)); \ + wait_for_completion(&((tsk_ctl)->completed)); \ + DBG_THR(("%s thr:%lx terminated OK\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ + (tsk_ctl)->thr_pid = -1; \ +} + + + +#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; \ @@ -437,10 +535,62 @@ 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)) +#include <linux/time.h> +#include <linux/wait.h> +#else +#include <linux/sched.h> + +#define __wait_event_interruptible_timeout(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +#define WL_DEV_IF(dev) ((wl_if_t*)netdev_priv(dev)) +#else +#define WL_DEV_IF(dev) ((wl_if_t*)(dev)->priv) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +#define WL_ISR(i, d, p) wl_isr((i), (d)) +#else +#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) +#endif + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #define netdev_priv(dev) dev->priv -#endif +#endif #endif diff --git a/src/include/miniopt.h b/src/include/miniopt.h index 6fbd7bb..f468420 100644 --- a/src/include/miniopt.h +++ b/src/include/miniopt.h @@ -1,7 +1,7 @@ /* * Command line options parser. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: miniopt.h,v 1.1.4.2 2009/01/14 23:46:41 Exp $ + * $Id: miniopt.h,v 1.3 2009-01-15 00:06:54 Exp $ */ diff --git a/src/include/msgtrace.h b/src/include/msgtrace.h index 594f984..721d421 100644 --- a/src/include/msgtrace.h +++ b/src/include/msgtrace.h @@ -1,7 +1,7 @@ /* * Trace messages sent over HBUS * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: msgtrace.h,v 1.2.8.1.4.2 2008/12/22 01:29:00 Exp $ + * $Id: msgtrace.h,v 1.4 2009-04-10 04:15:32 Exp $ */ #ifndef _MSGTRACE_H @@ -51,7 +51,7 @@ typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { #define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) -/* The hbus driver generates traces when sending a trace message. This causes endless traces. +/* The hbus driver generates traces when sending a trace message. This causes endless traces. * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. * This prevents endless traces but generates hasardous lost of traces only in bus device code. * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing @@ -61,10 +61,12 @@ extern bool msgtrace_hbus_trace; typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, uint16 hdrlen, uint8 *buf, uint16 buflen); - +extern void msgtrace_start(void); +extern void msgtrace_stop(void); extern void msgtrace_sent(void); extern void msgtrace_put(char *buf, int count); extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); +extern bool msgtrace_event_enabled(void); /* This marks the end of a packed structure section. */ #include <packed_section_end.h> diff --git a/src/include/osl.h b/src/include/osl.h index 4a87d8f..80248ee 100644 --- a/src/include/osl.h +++ b/src/include/osl.h @@ -1,7 +1,7 @@ /* * OS Abstraction Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,8 @@ * 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: osl.h,v 13.37.46.1 2008/10/25 00:31:52 Exp $ + * + * $Id: osl.h,v 13.44.96.1 2010-05-20 11:09:18 Exp $ */ @@ -36,8 +37,12 @@ typedef struct osl_dmainfo osldma_t; typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); + #include <linux_osl.h> +#ifndef PKTDBG_TRACE +#define PKTDBG_TRACE(osh, pkt, bit) +#endif @@ -51,5 +56,11 @@ typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) #endif +#if !defined(OSL_SYSUPTIME) +#define OSL_SYSUPTIME() (0) +#define OSL_SYSUPTIME_SUPPORT FALSE +#else +#define OSL_SYSUPTIME_SUPPORT TRUE +#endif #endif diff --git a/src/include/packed_section_end.h b/src/include/packed_section_end.h index 56b0b0f..5d4a876 100644 --- a/src/include/packed_section_end.h +++ b/src/include/packed_section_end.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -34,7 +34,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: packed_section_end.h,v 1.1.4.3 2008/12/10 00:40:00 Exp $ + * $Id: packed_section_end.h,v 1.4 2008-12-09 23:43:22 Exp $ */ diff --git a/src/include/packed_section_start.h b/src/include/packed_section_start.h index 974cd03..da2fed6 100644 --- a/src/include/packed_section_start.h +++ b/src/include/packed_section_start.h @@ -15,7 +15,7 @@ * #include <packed_section_end.h> * * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -34,7 +34,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: packed_section_start.h,v 1.1.4.3 2008/12/10 00:40:00 Exp $ + * $Id: packed_section_start.h,v 1.4.124.1 2010-09-17 00:47:03 Exp $ */ @@ -52,7 +52,7 @@ #if defined(__GNUC__) #define BWL_PRE_PACKED_STRUCT - #define BWL_POST_PACKED_STRUCT __attribute__((packed)) + #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) #elif defined(__CC_ARM) #define BWL_PRE_PACKED_STRUCT __packed #define BWL_POST_PACKED_STRUCT diff --git a/src/include/pcicfg.h b/src/include/pcicfg.h index ac8f073..fae063a 100644 --- a/src/include/pcicfg.h +++ b/src/include/pcicfg.h @@ -1,7 +1,7 @@ /* * pcicfg.h: PCI configuration constants and structures. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: pcicfg.h,v 1.41.12.3 2008/06/26 22:49:41 Exp $ + * $Id: pcicfg.h,v 1.50 2009-12-07 21:56:06 Exp $ */ diff --git a/src/include/proto/802.11.h b/src/include/proto/802.11.h index 3c18c98..2342cb3 100644 --- a/src/include/proto/802.11.h +++ b/src/include/proto/802.11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.20.8 2009/06/25 14:46:22 Exp $ + * $Id: 802.11.h,v 9.260.2.6 2010-12-15 21:41:14 Exp $ */ @@ -42,238 +42,255 @@ #include <packed_section_start.h> -#define DOT11_TU_TO_US 1024 +#define DOT11_TU_TO_US 1024 -#define DOT11_A3_HDR_LEN 24 -#define DOT11_A4_HDR_LEN 30 -#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN -#define DOT11_FCS_LEN 4 -#define DOT11_ICV_LEN 4 -#define DOT11_ICV_AES_LEN 8 -#define DOT11_QOS_LEN 2 -#define DOT11_HTC_LEN 4 +#define DOT11_A3_HDR_LEN 24 +#define DOT11_A4_HDR_LEN 30 +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN +#define DOT11_FCS_LEN 4 +#define DOT11_ICV_LEN 4 +#define DOT11_ICV_AES_LEN 8 +#define DOT11_QOS_LEN 2 +#define DOT11_HTC_LEN 4 -#define DOT11_KEY_INDEX_SHIFT 6 -#define DOT11_IV_LEN 4 -#define DOT11_IV_TKIP_LEN 8 -#define DOT11_IV_AES_OCB_LEN 4 -#define DOT11_IV_AES_CCM_LEN 8 -#define DOT11_IV_MAX_LEN 8 +#define DOT11_KEY_INDEX_SHIFT 6 +#define DOT11_IV_LEN 4 +#define DOT11_IV_TKIP_LEN 8 +#define DOT11_IV_AES_OCB_LEN 4 +#define DOT11_IV_AES_CCM_LEN 8 +#define DOT11_IV_MAX_LEN 8 -#define DOT11_MAX_MPDU_BODY_LEN 2304 +#define DOT11_MAX_MPDU_BODY_LEN 2304 -#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ DOT11_QOS_LEN + \ DOT11_IV_AES_CCM_LEN + \ DOT11_MAX_MPDU_BODY_LEN + \ DOT11_ICV_LEN + \ - DOT11_FCS_LEN) + DOT11_FCS_LEN) -#define DOT11_MAX_SSID_LEN 32 +#define DOT11_MAX_SSID_LEN 32 -#define DOT11_DEFAULT_RTS_LEN 2347 -#define DOT11_MAX_RTS_LEN 2347 +#define DOT11_DEFAULT_RTS_LEN 2347 +#define DOT11_MAX_RTS_LEN 2347 -#define DOT11_MIN_FRAG_LEN 256 -#define DOT11_MAX_FRAG_LEN 2346 -#define DOT11_DEFAULT_FRAG_LEN 2346 +#define DOT11_MIN_FRAG_LEN 256 +#define DOT11_MAX_FRAG_LEN 2346 +#define DOT11_DEFAULT_FRAG_LEN 2346 -#define DOT11_MIN_BEACON_PERIOD 1 -#define DOT11_MAX_BEACON_PERIOD 0xFFFF +#define DOT11_MIN_BEACON_PERIOD 1 +#define DOT11_MAX_BEACON_PERIOD 0xFFFF -#define DOT11_MIN_DTIM_PERIOD 1 -#define DOT11_MAX_DTIM_PERIOD 0xFF +#define DOT11_MIN_DTIM_PERIOD 1 +#define DOT11_MAX_DTIM_PERIOD 0xFF -#define DOT11_LLC_SNAP_HDR_LEN 8 -#define DOT11_OUI_LEN 3 +#define DOT11_LLC_SNAP_HDR_LEN 8 +#define DOT11_OUI_LEN 3 BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { - uint8 dsap; - uint8 ssap; - uint8 ctl; - uint8 oui[DOT11_OUI_LEN]; - uint16 type; + uint8 dsap; + uint8 ssap; + uint8 ctl; + uint8 oui[DOT11_OUI_LEN]; + uint16 type; } BWL_POST_PACKED_STRUCT; -#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) BWL_PRE_PACKED_STRUCT struct dot11_header { - uint16 fc; - uint16 durid; - struct ether_addr a1; - struct ether_addr a2; - struct ether_addr a3; - uint16 seq; - struct ether_addr a4; + uint16 fc; + uint16 durid; + struct ether_addr a1; + struct ether_addr a2; + struct ether_addr a3; + uint16 seq; + struct ether_addr a4; } BWL_POST_PACKED_STRUCT; BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { - uint16 fc; - uint16 durid; - struct ether_addr ra; - struct ether_addr ta; + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; } BWL_POST_PACKED_STRUCT; -#define DOT11_RTS_LEN 16 +#define DOT11_RTS_LEN 16 BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { - uint16 fc; - uint16 durid; - struct ether_addr ra; + uint16 fc; + uint16 durid; + struct ether_addr ra; } BWL_POST_PACKED_STRUCT; -#define DOT11_CTS_LEN 10 +#define DOT11_CTS_LEN 10 BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { - uint16 fc; - uint16 durid; - struct ether_addr ra; + uint16 fc; + uint16 durid; + struct ether_addr ra; } BWL_POST_PACKED_STRUCT; -#define DOT11_ACK_LEN 10 +#define DOT11_ACK_LEN 10 BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { - uint16 fc; - uint16 durid; - struct ether_addr bssid; - struct ether_addr ta; + uint16 fc; + uint16 durid; + struct ether_addr bssid; + struct ether_addr ta; } BWL_POST_PACKED_STRUCT; -#define DOT11_PS_POLL_LEN 16 +#define DOT11_PS_POLL_LEN 16 BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { - uint16 fc; - uint16 durid; - struct ether_addr ra; - struct ether_addr bssid; + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr bssid; } BWL_POST_PACKED_STRUCT; -#define DOT11_CS_END_LEN 16 +#define DOT11_CS_END_LEN 16 + BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { - uint8 category; - uint8 OUI[3]; - uint8 type; - uint8 subtype; - uint8 data[1040]; - struct dot11_action_wifi_vendor_specific* next_node; + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1040]; } BWL_POST_PACKED_STRUCT; - typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; -#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 -#define DOT11_BA_CTL_POLICY_NOACK 0x0001 -#define DOT11_BA_CTL_POLICY_MASK 0x0001 -#define DOT11_BA_CTL_MTID 0x0002 -#define DOT11_BA_CTL_COMPRESSED 0x0004 +BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { + uint8 category; + uint8 OUI[3]; + uint8 type; + uint8 subtype; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; +#define DOT11_ACTION_VS_HDR_LEN 6 + +#define BCM_ACTION_OUI_BYTE0 0x00 +#define BCM_ACTION_OUI_BYTE1 0x90 +#define BCM_ACTION_OUI_BYTE2 0x4c + + +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 +#define DOT11_BA_CTL_POLICY_MASK 0x0001 + +#define DOT11_BA_CTL_MTID 0x0002 +#define DOT11_BA_CTL_COMPRESSED 0x0004 -#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 -#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 -#define DOT11_BA_CTL_TID_MASK 0xF000 -#define DOT11_BA_CTL_TID_SHIFT 12 +#define DOT11_BA_CTL_TID_MASK 0xF000 +#define DOT11_BA_CTL_TID_SHIFT 12 BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { - uint16 fc; - uint16 durid; - struct ether_addr ra; - struct ether_addr ta; + uint16 fc; + uint16 durid; + struct ether_addr ra; + struct ether_addr ta; } BWL_POST_PACKED_STRUCT; -#define DOT11_CTL_HDR_LEN 16 +#define DOT11_CTL_HDR_LEN 16 BWL_PRE_PACKED_STRUCT struct dot11_bar { - uint16 bar_control; - uint16 seqnum; + uint16 bar_control; + uint16 seqnum; } BWL_POST_PACKED_STRUCT; -#define DOT11_BAR_LEN 4 +#define DOT11_BAR_LEN 4 -#define DOT11_BA_BITMAP_LEN 128 -#define DOT11_BA_CMP_BITMAP_LEN 8 +#define DOT11_BA_BITMAP_LEN 128 +#define DOT11_BA_CMP_BITMAP_LEN 8 BWL_PRE_PACKED_STRUCT struct dot11_ba { - uint16 ba_control; - uint16 seqnum; - uint8 bitmap[DOT11_BA_BITMAP_LEN]; + uint16 ba_control; + uint16 seqnum; + uint8 bitmap[DOT11_BA_BITMAP_LEN]; } BWL_POST_PACKED_STRUCT; -#define DOT11_BA_LEN 4 +#define DOT11_BA_LEN 4 BWL_PRE_PACKED_STRUCT struct dot11_management_header { - uint16 fc; - uint16 durid; - struct ether_addr da; - struct ether_addr sa; - struct ether_addr bssid; - uint16 seq; + uint16 fc; + uint16 durid; + struct ether_addr da; + struct ether_addr sa; + struct ether_addr bssid; + uint16 seq; } BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_HDR_LEN 24 +#define DOT11_MGMT_HDR_LEN 24 BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { - uint32 timestamp[2]; - uint16 beacon_interval; - uint16 capability; + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; } BWL_POST_PACKED_STRUCT; -#define DOT11_BCN_PRB_LEN 12 +#define DOT11_BCN_PRB_LEN 12 +#define DOT11_BCN_PRB_FIXED_LEN 12 BWL_PRE_PACKED_STRUCT struct dot11_auth { - uint16 alg; - uint16 seq; - uint16 status; + uint16 alg; + uint16 seq; + uint16 status; } BWL_POST_PACKED_STRUCT; -#define DOT11_AUTH_FIXED_LEN 6 +#define DOT11_AUTH_FIXED_LEN 6 BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { - uint16 capability; - uint16 listen; + uint16 capability; + uint16 listen; } BWL_POST_PACKED_STRUCT; -#define DOT11_ASSOC_REQ_FIXED_LEN 4 +#define DOT11_ASSOC_REQ_FIXED_LEN 4 BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { - uint16 capability; - uint16 listen; - struct ether_addr ap; + uint16 capability; + uint16 listen; + struct ether_addr ap; } BWL_POST_PACKED_STRUCT; -#define DOT11_REASSOC_REQ_FIXED_LEN 10 +#define DOT11_REASSOC_REQ_FIXED_LEN 10 BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { - uint16 capability; - uint16 status; - uint16 aid; + uint16 capability; + uint16 status; + uint16 aid; } BWL_POST_PACKED_STRUCT; +#define DOT11_ASSOC_RESP_FIXED_LEN 6 BWL_PRE_PACKED_STRUCT struct dot11_action_measure { - uint8 category; - uint8 action; - uint8 token; - uint8 data[1]; + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; } BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_MEASURE_LEN 3 +#define DOT11_ACTION_MEASURE_LEN 3 BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { - uint8 category; - uint8 action; - uint8 ch_width; + uint8 category; + uint8 action; + uint8 ch_width; } BWL_POST_PACKED_STRUCT; BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { - uint8 category; - uint8 action; - uint8 control; + uint8 category; + uint8 action; + uint8 control; } BWL_POST_PACKED_STRUCT; -#define SM_PWRSAVE_ENABLE 1 -#define SM_PWRSAVE_MODE 2 +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { @@ -296,7 +313,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { uint8 margin; } BWL_POST_PACKED_STRUCT; typedef struct dot11_tpc_rep dot11_tpc_rep_t; -#define DOT11_MNG_IE_TPC_REPORT_LEN 2 +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { uint8 id; @@ -308,96 +325,106 @@ typedef struct dot11_supp_channels dot11_supp_channels_t; BWL_PRE_PACKED_STRUCT struct dot11_extch { - uint8 id; - uint8 len; - uint8 extch; + uint8 id; + uint8 len; + uint8 extch; } BWL_POST_PACKED_STRUCT; typedef struct dot11_extch dot11_extch_ie_t; BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; - uint8 extch; + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; + uint8 extch; } BWL_POST_PACKED_STRUCT; typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; -#define BRCM_EXTCH_IE_LEN 5 -#define BRCM_EXTCH_IE_TYPE 53 -#define DOT11_EXTCH_IE_LEN 1 -#define DOT11_EXT_CH_MASK 0x03 -#define DOT11_EXT_CH_UPPER 0x01 -#define DOT11_EXT_CH_LOWER 0x03 -#define DOT11_EXT_CH_NONE 0x00 +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 +#define DOT11_EXT_CH_UPPER 0x01 +#define DOT11_EXT_CH_LOWER 0x03 +#define DOT11_EXT_CH_NONE 0x00 BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { - uint8 category; - uint8 action; - uint8 data[1]; + uint8 category; + uint8 action; + uint8 data[1]; } BWL_POST_PACKED_STRUCT; -#define DOT11_ACTION_FRMHDR_LEN 2 +#define DOT11_ACTION_FRMHDR_LEN 2 BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { - uint8 id; - uint8 len; - uint8 mode; - uint8 channel; - uint8 count; + uint8 id; + uint8 len; + uint8 mode; + uint8 channel; + uint8 count; } BWL_POST_PACKED_STRUCT; typedef struct dot11_channel_switch dot11_chan_switch_ie_t; -#define DOT11_SWITCH_IE_LEN 3 +#define DOT11_SWITCH_IE_LEN 3 -#define DOT11_CSA_MODE_ADVISORY 0 -#define DOT11_CSA_MODE_NO_TX 1 +#define DOT11_CSA_MODE_ADVISORY 0 +#define DOT11_CSA_MODE_NO_TX 1 BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { - uint8 category; - uint8 action; - dot11_chan_switch_ie_t chan_switch_ie; - dot11_brcm_extch_ie_t extch_ie; + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; + dot11_brcm_extch_ie_t extch_ie; +} BWL_POST_PACKED_STRUCT; + +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; - uint8 mode; - uint8 reg; - uint8 channel; - uint8 count; + uint8 id; + uint8 len; + 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 +#define DOT11_EXT_CSA_IE_LEN 4 BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { - uint8 category; - uint8 action; - dot11_ext_csa_ie_t chan_switch_ie; + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; +} 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; BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { - uint8 id; - uint8 len; - uint8 info; + uint8 id; + uint8 len; + uint8 info; } BWL_POST_PACKED_STRUCT; typedef struct dot11_obss_coex dot11_obss_coex_t; -#define DOT11_OBSS_COEXINFO_LEN 1 +#define DOT11_OBSS_COEXINFO_LEN 1 -#define DOT11_OBSS_COEX_INFO_REQ 0x01 -#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 -#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 +#define DOT11_OBSS_COEX_INFO_REQ 0x01 +#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 +#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { - uint8 id; - uint8 len; - uint8 regclass; - uint8 chanlist[1]; + uint8 id; + uint8 len; + uint8 regclass; + uint8 chanlist[1]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; -#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 +#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { uint8 id; @@ -405,28 +432,38 @@ BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { uint8 cap; } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap_ie dot11_extcap_ie_t; -#define DOT11_EXTCAP_LEN 1 +#define DOT11_EXTCAP_LEN 1 -#define DOT11_MEASURE_TYPE_BASIC 0 -#define DOT11_MEASURE_TYPE_CCA 1 -#define DOT11_MEASURE_TYPE_RPI 2 +#define DOT11_MEASURE_TYPE_BASIC 0 +#define DOT11_MEASURE_TYPE_CCA 1 +#define DOT11_MEASURE_TYPE_RPI 2 +#define DOT11_MEASURE_TYPE_CHLOAD 3 +#define DOT11_MEASURE_TYPE_NOISE 4 +#define DOT11_MEASURE_TYPE_BEACON 5 +#define DOT11_MEASURE_TYPE_FRAME 6 +#define DOT11_MEASURE_TYPE_STATS 7 +#define DOT11_MEASURE_TYPE_LCI 8 +#define DOT11_MEASURE_TYPE_TXSTREAM 9 +#define DOT11_MEASURE_TYPE_PAUSE 255 -#define DOT11_MEASURE_MODE_ENABLE (1<<1) -#define DOT11_MEASURE_MODE_REQUEST (1<<2) -#define DOT11_MEASURE_MODE_REPORT (1<<3) +#define DOT11_MEASURE_MODE_PARALLEL (1<<0) +#define DOT11_MEASURE_MODE_ENABLE (1<<1) +#define DOT11_MEASURE_MODE_REQUEST (1<<2) +#define DOT11_MEASURE_MODE_REPORT (1<<3) +#define DOT11_MEASURE_MODE_DUR (1<<4) -#define DOT11_MEASURE_MODE_LATE (1<<0) -#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) -#define DOT11_MEASURE_MODE_REFUSED (1<<2) +#define DOT11_MEASURE_MODE_LATE (1<<0) +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) +#define DOT11_MEASURE_MODE_REFUSED (1<<2) -#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) -#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) -#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) -#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) -#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) BWL_PRE_PACKED_STRUCT struct dot11_meas_req { uint8 id; @@ -439,9 +476,9 @@ BWL_PRE_PACKED_STRUCT struct dot11_meas_req { uint16 duration; } BWL_POST_PACKED_STRUCT; typedef struct dot11_meas_req dot11_meas_req_t; -#define DOT11_MNG_IE_MREQ_LEN 14 +#define DOT11_MNG_IE_MREQ_LEN 14 -#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { uint8 id; @@ -463,7 +500,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { typedef struct dot11_meas_rep dot11_meas_rep_t; -#define DOT11_MNG_IE_MREP_FIXED_LEN 3 +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { uint8 channel; @@ -472,15 +509,15 @@ BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { uint8 map; } BWL_POST_PACKED_STRUCT; typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; -#define DOT11_MEASURE_BASIC_REP_LEN 12 +#define DOT11_MEASURE_BASIC_REP_LEN 12 BWL_PRE_PACKED_STRUCT struct dot11_quiet { uint8 id; uint8 len; - uint8 count; - uint8 period; - uint16 duration; - uint16 offset; + uint8 count; + uint8 period; + uint16 duration; + uint16 offset; } BWL_POST_PACKED_STRUCT; typedef struct dot11_quiet dot11_quiet_t; @@ -500,26 +537,28 @@ BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; -#define WME_OUI "\x00\x50\xf2" -#define WME_VER 1 -#define WME_TYPE 2 -#define WME_SUBTYPE_IE 0 -#define WME_SUBTYPE_PARAM_IE 1 -#define WME_SUBTYPE_TSPEC 2 +#define WME_OUI "\x00\x50\xf2" +#define WME_OUI_LEN 3 +#define WME_OUI_TYPE 2 +#define WME_VER 1 +#define WME_TYPE 2 +#define WME_SUBTYPE_IE 0 +#define WME_SUBTYPE_PARAM_IE 1 +#define WME_SUBTYPE_TSPEC 2 -#define AC_BE 0 -#define AC_BK 1 -#define AC_VI 2 -#define AC_VO 3 -#define AC_COUNT 4 +#define AC_BE 0 +#define AC_BK 1 +#define AC_VI 2 +#define AC_VO 3 +#define AC_COUNT 4 -typedef uint8 ac_bitmap_t; +typedef uint8 ac_bitmap_t; -#define AC_BITMAP_NONE 0x0 -#define AC_BITMAP_ALL 0xf -#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) -#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) +#define AC_BITMAP_NONE 0x0 +#define AC_BITMAP_ALL 0xf +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) +#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) #define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) @@ -531,12 +570,12 @@ BWL_PRE_PACKED_STRUCT struct wme_ie { uint8 qosinfo; } BWL_POST_PACKED_STRUCT; typedef struct wme_ie wme_ie_t; -#define WME_IE_LEN 7 +#define WME_IE_LEN 7 BWL_PRE_PACKED_STRUCT struct edcf_acparam { - uint8 ACI; - uint8 ECW; - uint16 TXOP; + uint8 ACI; + uint8 ECW; + uint16 TXOP; } BWL_POST_PACKED_STRUCT; typedef struct edcf_acparam edcf_acparam_t; @@ -596,32 +635,35 @@ typedef struct wme_param_ie wme_param_ie_t; #define EDCF_TXOP2USEC(txop) ((txop) << 5) -#define EDCF_AC_BE_ACI_STA 0x03 -#define EDCF_AC_BE_ECW_STA 0xA4 -#define EDCF_AC_BE_TXOP_STA 0x0000 -#define EDCF_AC_BK_ACI_STA 0x27 -#define EDCF_AC_BK_ECW_STA 0xA4 -#define EDCF_AC_BK_TXOP_STA 0x0000 -#define EDCF_AC_VI_ACI_STA 0x42 -#define EDCF_AC_VI_ECW_STA 0x43 -#define EDCF_AC_VI_TXOP_STA 0x005e -#define EDCF_AC_VO_ACI_STA 0x62 -#define EDCF_AC_VO_ECW_STA 0x32 -#define EDCF_AC_VO_TXOP_STA 0x002f - - -#define EDCF_AC_BE_ACI_AP 0x03 -#define EDCF_AC_BE_ECW_AP 0x64 -#define EDCF_AC_BE_TXOP_AP 0x0000 -#define EDCF_AC_BK_ACI_AP 0x27 -#define EDCF_AC_BK_ECW_AP 0xA4 -#define EDCF_AC_BK_TXOP_AP 0x0000 -#define EDCF_AC_VI_ACI_AP 0x41 -#define EDCF_AC_VI_ECW_AP 0x43 -#define EDCF_AC_VI_TXOP_AP 0x005e -#define EDCF_AC_VO_ACI_AP 0x61 -#define EDCF_AC_VO_ECW_AP 0x32 -#define EDCF_AC_VO_TXOP_AP 0x002f +#define NON_EDCF_AC_BE_ACI_STA 0x02 + + +#define EDCF_AC_BE_ACI_STA 0x03 +#define EDCF_AC_BE_ECW_STA 0xA4 +#define EDCF_AC_BE_TXOP_STA 0x0000 +#define EDCF_AC_BK_ACI_STA 0x27 +#define EDCF_AC_BK_ECW_STA 0xA4 +#define EDCF_AC_BK_TXOP_STA 0x0000 +#define EDCF_AC_VI_ACI_STA 0x42 +#define EDCF_AC_VI_ECW_STA 0x43 +#define EDCF_AC_VI_TXOP_STA 0x005e +#define EDCF_AC_VO_ACI_STA 0x62 +#define EDCF_AC_VO_ECW_STA 0x32 +#define EDCF_AC_VO_TXOP_STA 0x002f + + +#define EDCF_AC_BE_ACI_AP 0x03 +#define EDCF_AC_BE_ECW_AP 0x64 +#define EDCF_AC_BE_TXOP_AP 0x0000 +#define EDCF_AC_BK_ACI_AP 0x27 +#define EDCF_AC_BK_ECW_AP 0xA4 +#define EDCF_AC_BK_TXOP_AP 0x0000 +#define EDCF_AC_VI_ACI_AP 0x41 +#define EDCF_AC_VI_ECW_AP 0x43 +#define EDCF_AC_VI_TXOP_AP 0x005e +#define EDCF_AC_VO_ACI_AP 0x61 +#define EDCF_AC_VO_ECW_AP 0x32 +#define EDCF_AC_VO_TXOP_AP 0x002f BWL_PRE_PACKED_STRUCT struct edca_param_ie { @@ -639,773 +681,1049 @@ BWL_PRE_PACKED_STRUCT struct qos_cap_ie { typedef struct qos_cap_ie qos_cap_ie_t; BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { - uint8 id; + uint8 id; uint8 length; - uint16 station_count; - uint8 channel_utilization; - uint16 aac; + uint16 station_count; + uint8 channel_utilization; + uint16 aac; } BWL_POST_PACKED_STRUCT; typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; -#define FIXED_MSDU_SIZE 0x8000 -#define MSDU_SIZE_MASK 0x7fff +#define FIXED_MSDU_SIZE 0x8000 +#define MSDU_SIZE_MASK 0x7fff -#define INTEGER_SHIFT 13 -#define FRACTION_MASK 0x1FFF +#define INTEGER_SHIFT 13 +#define FRACTION_MASK 0x1FFF BWL_PRE_PACKED_STRUCT struct dot11_management_notification { - uint8 category; + uint8 category; uint8 action; uint8 token; uint8 status; - uint8 data[1]; + uint8 data[1]; } BWL_POST_PACKED_STRUCT; -#define DOT11_MGMT_NOTIFICATION_LEN 4 +#define DOT11_MGMT_NOTIFICATION_LEN 4 -#define WME_ADDTS_REQUEST 0 -#define WME_ADDTS_RESPONSE 1 -#define WME_DELTS_REQUEST 2 +#define WME_ADDTS_REQUEST 0 +#define WME_ADDTS_RESPONSE 1 +#define WME_DELTS_REQUEST 2 -#define WME_ADMISSION_ACCEPTED 0 -#define WME_INVALID_PARAMETERS 1 -#define WME_ADMISSION_REFUSED 3 +#define WME_ADMISSION_ACCEPTED 0 +#define WME_INVALID_PARAMETERS 1 +#define WME_ADMISSION_REFUSED 3 #define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) -#define DOT11_OPEN_SYSTEM 0 -#define DOT11_SHARED_KEY 1 - -#define DOT11_OPEN_SHARED 2 -#define DOT11_CHALLENGE_LEN 128 - - -#define FC_PVER_MASK 0x3 -#define FC_PVER_SHIFT 0 -#define FC_TYPE_MASK 0xC -#define FC_TYPE_SHIFT 2 -#define FC_SUBTYPE_MASK 0xF0 -#define FC_SUBTYPE_SHIFT 4 -#define FC_TODS 0x100 -#define FC_TODS_SHIFT 8 -#define FC_FROMDS 0x200 -#define FC_FROMDS_SHIFT 9 -#define FC_MOREFRAG 0x400 -#define FC_MOREFRAG_SHIFT 10 -#define FC_RETRY 0x800 -#define FC_RETRY_SHIFT 11 -#define FC_PM 0x1000 -#define FC_PM_SHIFT 12 -#define FC_MOREDATA 0x2000 -#define FC_MOREDATA_SHIFT 13 -#define FC_WEP 0x4000 -#define FC_WEP_SHIFT 14 -#define FC_ORDER 0x8000 -#define FC_ORDER_SHIFT 15 - - -#define SEQNUM_SHIFT 4 -#define SEQNUM_MAX 0x1000 -#define FRAGNUM_MASK 0xF - - - - -#define FC_TYPE_MNG 0 -#define FC_TYPE_CTL 1 -#define FC_TYPE_DATA 2 - - -#define FC_SUBTYPE_ASSOC_REQ 0 -#define FC_SUBTYPE_ASSOC_RESP 1 -#define FC_SUBTYPE_REASSOC_REQ 2 -#define FC_SUBTYPE_REASSOC_RESP 3 -#define FC_SUBTYPE_PROBE_REQ 4 -#define FC_SUBTYPE_PROBE_RESP 5 -#define FC_SUBTYPE_BEACON 8 -#define FC_SUBTYPE_ATIM 9 -#define FC_SUBTYPE_DISASSOC 10 -#define FC_SUBTYPE_AUTH 11 -#define FC_SUBTYPE_DEAUTH 12 -#define FC_SUBTYPE_ACTION 13 -#define FC_SUBTYPE_ACTION_NOACK 14 - - -#define FC_SUBTYPE_CTL_WRAPPER 7 -#define FC_SUBTYPE_BLOCKACK_REQ 8 -#define FC_SUBTYPE_BLOCKACK 9 -#define FC_SUBTYPE_PS_POLL 10 -#define FC_SUBTYPE_RTS 11 -#define FC_SUBTYPE_CTS 12 -#define FC_SUBTYPE_ACK 13 -#define FC_SUBTYPE_CF_END 14 -#define FC_SUBTYPE_CF_END_ACK 15 +#define DOT11_OPEN_SYSTEM 0 +#define DOT11_SHARED_KEY 1 +#define DOT11_OPEN_SHARED 2 +#define DOT11_FAST_BSS 3 +#define DOT11_CHALLENGE_LEN 128 + + +#define FC_PVER_MASK 0x3 +#define FC_PVER_SHIFT 0 +#define FC_TYPE_MASK 0xC +#define FC_TYPE_SHIFT 2 +#define FC_SUBTYPE_MASK 0xF0 +#define FC_SUBTYPE_SHIFT 4 +#define FC_TODS 0x100 +#define FC_TODS_SHIFT 8 +#define FC_FROMDS 0x200 +#define FC_FROMDS_SHIFT 9 +#define FC_MOREFRAG 0x400 +#define FC_MOREFRAG_SHIFT 10 +#define FC_RETRY 0x800 +#define FC_RETRY_SHIFT 11 +#define FC_PM 0x1000 +#define FC_PM_SHIFT 12 +#define FC_MOREDATA 0x2000 +#define FC_MOREDATA_SHIFT 13 +#define FC_WEP 0x4000 +#define FC_WEP_SHIFT 14 +#define FC_ORDER 0x8000 +#define FC_ORDER_SHIFT 15 + + +#define SEQNUM_SHIFT 4 +#define SEQNUM_MAX 0x1000 +#define FRAGNUM_MASK 0xF + + + + +#define FC_TYPE_MNG 0 +#define FC_TYPE_CTL 1 +#define FC_TYPE_DATA 2 + + +#define FC_SUBTYPE_ASSOC_REQ 0 +#define FC_SUBTYPE_ASSOC_RESP 1 +#define FC_SUBTYPE_REASSOC_REQ 2 +#define FC_SUBTYPE_REASSOC_RESP 3 +#define FC_SUBTYPE_PROBE_REQ 4 +#define FC_SUBTYPE_PROBE_RESP 5 +#define FC_SUBTYPE_BEACON 8 +#define FC_SUBTYPE_ATIM 9 +#define FC_SUBTYPE_DISASSOC 10 +#define FC_SUBTYPE_AUTH 11 +#define FC_SUBTYPE_DEAUTH 12 +#define FC_SUBTYPE_ACTION 13 +#define FC_SUBTYPE_ACTION_NOACK 14 + + +#define FC_SUBTYPE_CTL_WRAPPER 7 +#define FC_SUBTYPE_BLOCKACK_REQ 8 +#define FC_SUBTYPE_BLOCKACK 9 +#define FC_SUBTYPE_PS_POLL 10 +#define FC_SUBTYPE_RTS 11 +#define FC_SUBTYPE_CTS 12 +#define FC_SUBTYPE_ACK 13 +#define FC_SUBTYPE_CF_END 14 +#define FC_SUBTYPE_CF_END_ACK 15 -#define FC_SUBTYPE_DATA 0 -#define FC_SUBTYPE_DATA_CF_ACK 1 -#define FC_SUBTYPE_DATA_CF_POLL 2 -#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 -#define FC_SUBTYPE_NULL 4 -#define FC_SUBTYPE_CF_ACK 5 -#define FC_SUBTYPE_CF_POLL 6 -#define FC_SUBTYPE_CF_ACK_POLL 7 -#define FC_SUBTYPE_QOS_DATA 8 -#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 -#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 -#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 -#define FC_SUBTYPE_QOS_NULL 12 -#define FC_SUBTYPE_QOS_CF_POLL 14 -#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 +#define FC_SUBTYPE_DATA 0 +#define FC_SUBTYPE_DATA_CF_ACK 1 +#define FC_SUBTYPE_DATA_CF_POLL 2 +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 +#define FC_SUBTYPE_NULL 4 +#define FC_SUBTYPE_CF_ACK 5 +#define FC_SUBTYPE_CF_POLL 6 +#define FC_SUBTYPE_CF_ACK_POLL 7 +#define FC_SUBTYPE_QOS_DATA 8 +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 +#define FC_SUBTYPE_QOS_NULL 12 +#define FC_SUBTYPE_QOS_CF_POLL 14 +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 -#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) -#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) -#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) -#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) -#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) -#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) -#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) -#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) -#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) -#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) -#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) -#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) -#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) -#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) -#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) -#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) -#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) -#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) -#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) -#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) - -#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) -#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) -#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) -#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) -#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) -#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) -#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) -#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) -#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) - -#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) -#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) -#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) -#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) -#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) -#define QOS_PRIO_SHIFT 0 -#define QOS_PRIO_MASK 0x0007 -#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) +#define QOS_PRIO_SHIFT 0 +#define QOS_PRIO_MASK 0x0007 +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) + - -#define QOS_TID_SHIFT 0 -#define QOS_TID_MASK 0x000f -#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) +#define QOS_TID_SHIFT 0 +#define QOS_TID_MASK 0x000f +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) + + +#define QOS_EOSP_SHIFT 4 +#define QOS_EOSP_MASK 0x0010 +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) + + +#define QOS_ACK_NORMAL_ACK 0 +#define QOS_ACK_NO_ACK 1 +#define QOS_ACK_NO_EXP_ACK 2 +#define QOS_ACK_BLOCK_ACK 3 +#define QOS_ACK_SHIFT 5 +#define QOS_ACK_MASK 0x0060 +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) -#define QOS_EOSP_SHIFT 4 -#define QOS_EOSP_MASK 0x0010 -#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) - - -#define QOS_ACK_NORMAL_ACK 0 -#define QOS_ACK_NO_ACK 1 -#define QOS_ACK_NO_EXP_ACK 2 -#define QOS_ACK_BLOCK_ACK 3 -#define QOS_ACK_SHIFT 5 -#define QOS_ACK_MASK 0x0060 -#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) +#define QOS_AMSDU_SHIFT 7 +#define QOS_AMSDU_MASK 0x0080 + + + + + + +#define DOT11_MNG_AUTH_ALGO_LEN 2 +#define DOT11_MNG_AUTH_SEQ_LEN 2 +#define DOT11_MNG_BEACON_INT_LEN 2 +#define DOT11_MNG_CAP_LEN 2 +#define DOT11_MNG_AP_ADDR_LEN 6 +#define DOT11_MNG_LISTEN_INT_LEN 2 +#define DOT11_MNG_REASON_LEN 2 +#define DOT11_MNG_AID_LEN 2 +#define DOT11_MNG_STATUS_LEN 2 +#define DOT11_MNG_TIMESTAMP_LEN 8 + + +#define DOT11_AID_MASK 0x3fff + + +#define DOT11_RC_RESERVED 0 +#define DOT11_RC_UNSPECIFIED 1 +#define DOT11_RC_AUTH_INVAL 2 +#define DOT11_RC_DEAUTH_LEAVING 3 +#define DOT11_RC_INACTIVITY 4 +#define DOT11_RC_BUSY 5 +#define DOT11_RC_INVAL_CLASS_2 6 +#define DOT11_RC_INVAL_CLASS_3 7 +#define DOT11_RC_DISASSOC_LEAVING 8 +#define DOT11_RC_NOT_AUTH 9 +#define DOT11_RC_BAD_PC 10 +#define DOT11_RC_BAD_CHANNELS 11 + + + +#define DOT11_RC_UNSPECIFIED_QOS 32 +#define DOT11_RC_INSUFFCIENT_BW 33 +#define DOT11_RC_EXCESSIVE_FRAMES 34 +#define DOT11_RC_TX_OUTSIDE_TXOP 35 +#define DOT11_RC_LEAVING_QBSS 36 +#define DOT11_RC_BAD_MECHANISM 37 +#define DOT11_RC_SETUP_NEEDED 38 +#define DOT11_RC_TIMEOUT 39 + +#define DOT11_RC_MAX 23 + + +#define DOT11_SC_SUCCESS 0 +#define DOT11_SC_FAILURE 1 +#define DOT11_SC_CAP_MISMATCH 10 +#define DOT11_SC_REASSOC_FAIL 11 +#define DOT11_SC_ASSOC_FAIL 12 +#define DOT11_SC_AUTH_MISMATCH 13 +#define DOT11_SC_AUTH_SEQ 14 +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 +#define DOT11_SC_AUTH_TIMEOUT 16 +#define DOT11_SC_ASSOC_BUSY_FAIL 17 +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 +#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 +#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 + +#define DOT11_SC_DECLINED 37 +#define DOT11_SC_INVALID_PARAMS 38 +#define DOT11_SC_INVALID_AKMP 43 +#define DOT11_SC_INVALID_MDID 54 +#define DOT11_SC_INVALID_FTIE 55 + + +#define DOT11_MNG_DS_PARAM_LEN 1 +#define DOT11_MNG_IBSS_PARAM_LEN 2 + + +#define DOT11_MNG_TIM_FIXED_LEN 3 +#define DOT11_MNG_TIM_DTIM_COUNT 0 +#define DOT11_MNG_TIM_DTIM_PERIOD 1 +#define DOT11_MNG_TIM_BITMAP_CTL 2 +#define DOT11_MNG_TIM_PVB 3 + + +#define TLV_TAG_OFF 0 +#define TLV_LEN_OFF 1 +#define TLV_HDR_LEN 2 +#define TLV_BODY_OFF 2 + + +#define DOT11_MNG_SSID_ID 0 +#define DOT11_MNG_RATES_ID 1 +#define DOT11_MNG_FH_PARMS_ID 2 +#define DOT11_MNG_DS_PARMS_ID 3 +#define DOT11_MNG_CF_PARMS_ID 4 +#define DOT11_MNG_TIM_ID 5 +#define DOT11_MNG_IBSS_PARMS_ID 6 +#define DOT11_MNG_COUNTRY_ID 7 +#define DOT11_MNG_HOPPING_PARMS_ID 8 +#define DOT11_MNG_HOPPING_TABLE_ID 9 +#define DOT11_MNG_REQUEST_ID 10 +#define DOT11_MNG_QBSS_LOAD_ID 11 +#define DOT11_MNG_EDCA_PARAM_ID 12 +#define DOT11_MNG_CHALLENGE_ID 16 +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 +#define DOT11_MNG_PWR_CAP_ID 33 +#define DOT11_MNG_TPC_REQUEST_ID 34 +#define DOT11_MNG_TPC_REPORT_ID 35 +#define DOT11_MNG_SUPP_CHANNELS_ID 36 +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 +#define DOT11_MNG_MEASURE_REQUEST_ID 38 +#define DOT11_MNG_MEASURE_REPORT_ID 39 +#define DOT11_MNG_QUIET_ID 40 +#define DOT11_MNG_IBSS_DFS_ID 41 +#define DOT11_MNG_ERP_ID 42 +#define DOT11_MNG_TS_DELAY_ID 43 +#define DOT11_MNG_HT_CAP 45 +#define DOT11_MNG_QOS_CAP_ID 46 +#define DOT11_MNG_NONERP_ID 47 +#define DOT11_MNG_RSN_ID 48 +#define DOT11_MNG_EXT_RATES_ID 50 +#define DOT11_MNG_AP_CHREP_ID 51 +#define DOT11_MNG_NBR_REP_ID 52 +#define DOT11_MNG_MDIE_ID 54 +#define DOT11_MNG_FTIE_ID 55 +#define DOT11_MNG_FT_TI_ID 56 +#define DOT11_MNG_REGCLASS_ID 59 +#define DOT11_MNG_EXT_CSA_ID 60 +#define DOT11_MNG_HT_ADD 61 +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 + + +#define DOT11_MNG_RRM_CAP_ID 70 +#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 +#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 +#define DOT11_MNG_HT_OBSS_ID 74 +#define DOT11_MNG_EXT_CAP 127 +#define DOT11_MNG_WPA_ID 221 +#define DOT11_MNG_PROPR_ID 221 + +#define DOT11_MNG_VS_ID 221 + + +#define DOT11_RATE_BASIC 0x80 +#define DOT11_RATE_MASK 0x7F + + +#define DOT11_MNG_ERP_LEN 1 +#define DOT11_MNG_NONERP_PRESENT 0x01 +#define DOT11_MNG_USE_PROTECTION 0x02 +#define DOT11_MNG_BARKER_PREAMBLE 0x04 + +#define DOT11_MGN_TS_DELAY_LEN 4 +#define TS_DELAY_FIELD_SIZE 4 + + +#define DOT11_CAP_ESS 0x0001 +#define DOT11_CAP_IBSS 0x0002 +#define DOT11_CAP_POLLABLE 0x0004 +#define DOT11_CAP_POLL_RQ 0x0008 +#define DOT11_CAP_PRIVACY 0x0010 +#define DOT11_CAP_SHORT 0x0020 +#define DOT11_CAP_PBCC 0x0040 +#define DOT11_CAP_AGILITY 0x0080 +#define DOT11_CAP_SPECTRUM 0x0100 +#define DOT11_CAP_SHORTSLOT 0x0400 +#define DOT11_CAP_RRM 0x1000 +#define DOT11_CAP_CCK_OFDM 0x2000 + + +#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 + + +#define DOT11_ACTION_HDR_LEN 2 +#define DOT11_ACTION_CAT_OFF 0 +#define DOT11_ACTION_ACT_OFF 1 + + +#define DOT11_ACTION_CAT_ERR_MASK 0x80 +#define DOT11_ACTION_CAT_MASK 0x7F +#define DOT11_ACTION_CAT_SPECT_MNG 0 +#define DOT11_ACTION_CAT_QOS 1 +#define DOT11_ACTION_CAT_DLS 2 +#define DOT11_ACTION_CAT_BLOCKACK 3 +#define DOT11_ACTION_CAT_PUBLIC 4 +#define DOT11_ACTION_CAT_RRM 5 +#define DOT11_ACTION_CAT_FBT 6 +#define DOT11_ACTION_CAT_HT 7 +#define DOT11_ACTION_CAT_BSSMGMT 10 +#define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VS 127 + + +#define DOT11_SM_ACTION_M_REQ 0 +#define DOT11_SM_ACTION_M_REP 1 +#define DOT11_SM_ACTION_TPC_REQ 2 +#define DOT11_SM_ACTION_TPC_REP 3 +#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 +#define DOT11_SM_ACTION_EXT_CSA 5 + + +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 +#define DOT11_ACTION_ID_HT_MIMO_PS 1 + + +#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 +#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 + + +#define DOT11_BA_ACTION_ADDBA_REQ 0 +#define DOT11_BA_ACTION_ADDBA_RESP 1 +#define DOT11_BA_ACTION_DELBA 2 -#define QOS_AMSDU_SHIFT 7 -#define QOS_AMSDU_MASK 0x0080 - - - - - - -#define DOT11_MNG_AUTH_ALGO_LEN 2 -#define DOT11_MNG_AUTH_SEQ_LEN 2 -#define DOT11_MNG_BEACON_INT_LEN 2 -#define DOT11_MNG_CAP_LEN 2 -#define DOT11_MNG_AP_ADDR_LEN 6 -#define DOT11_MNG_LISTEN_INT_LEN 2 -#define DOT11_MNG_REASON_LEN 2 -#define DOT11_MNG_AID_LEN 2 -#define DOT11_MNG_STATUS_LEN 2 -#define DOT11_MNG_TIMESTAMP_LEN 8 - - -#define DOT11_AID_MASK 0x3fff - - -#define DOT11_RC_RESERVED 0 -#define DOT11_RC_UNSPECIFIED 1 -#define DOT11_RC_AUTH_INVAL 2 -#define DOT11_RC_DEAUTH_LEAVING 3 -#define DOT11_RC_INACTIVITY 4 -#define DOT11_RC_BUSY 5 -#define DOT11_RC_INVAL_CLASS_2 6 -#define DOT11_RC_INVAL_CLASS_3 7 -#define DOT11_RC_DISASSOC_LEAVING 8 -#define DOT11_RC_NOT_AUTH 9 -#define DOT11_RC_BAD_PC 10 -#define DOT11_RC_BAD_CHANNELS 11 - - - -#define DOT11_RC_UNSPECIFIED_QOS 32 -#define DOT11_RC_INSUFFCIENT_BW 33 -#define DOT11_RC_EXCESSIVE_FRAMES 34 -#define DOT11_RC_TX_OUTSIDE_TXOP 35 -#define DOT11_RC_LEAVING_QBSS 36 -#define DOT11_RC_BAD_MECHANISM 37 -#define DOT11_RC_SETUP_NEEDED 38 -#define DOT11_RC_TIMEOUT 39 - -#define DOT11_RC_MAX 23 - - -#define DOT11_SC_SUCCESS 0 -#define DOT11_SC_FAILURE 1 -#define DOT11_SC_CAP_MISMATCH 10 -#define DOT11_SC_REASSOC_FAIL 11 -#define DOT11_SC_ASSOC_FAIL 12 -#define DOT11_SC_AUTH_MISMATCH 13 -#define DOT11_SC_AUTH_SEQ 14 -#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 -#define DOT11_SC_AUTH_TIMEOUT 16 -#define DOT11_SC_ASSOC_BUSY_FAIL 17 -#define DOT11_SC_ASSOC_RATE_MISMATCH 18 -#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 -#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 -#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 -#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 -#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 -#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 -#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 -#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 -#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 - -#define DOT11_SC_DECLINED 37 -#define DOT11_SC_INVALID_PARAMS 38 - - -#define DOT11_MNG_DS_PARAM_LEN 1 -#define DOT11_MNG_IBSS_PARAM_LEN 2 - - -#define DOT11_MNG_TIM_FIXED_LEN 3 -#define DOT11_MNG_TIM_DTIM_COUNT 0 -#define DOT11_MNG_TIM_DTIM_PERIOD 1 -#define DOT11_MNG_TIM_BITMAP_CTL 2 -#define DOT11_MNG_TIM_PVB 3 - - -#define TLV_TAG_OFF 0 -#define TLV_LEN_OFF 1 -#define TLV_HDR_LEN 2 -#define TLV_BODY_OFF 2 - - -#define DOT11_MNG_SSID_ID 0 -#define DOT11_MNG_RATES_ID 1 -#define DOT11_MNG_FH_PARMS_ID 2 -#define DOT11_MNG_DS_PARMS_ID 3 -#define DOT11_MNG_CF_PARMS_ID 4 -#define DOT11_MNG_TIM_ID 5 -#define DOT11_MNG_IBSS_PARMS_ID 6 -#define DOT11_MNG_COUNTRY_ID 7 -#define DOT11_MNG_HOPPING_PARMS_ID 8 -#define DOT11_MNG_HOPPING_TABLE_ID 9 -#define DOT11_MNG_REQUEST_ID 10 -#define DOT11_MNG_QBSS_LOAD_ID 11 -#define DOT11_MNG_EDCA_PARAM_ID 12 -#define DOT11_MNG_CHALLENGE_ID 16 -#define DOT11_MNG_PWR_CONSTRAINT_ID 32 -#define DOT11_MNG_PWR_CAP_ID 33 -#define DOT11_MNG_TPC_REQUEST_ID 34 -#define DOT11_MNG_TPC_REPORT_ID 35 -#define DOT11_MNG_SUPP_CHANNELS_ID 36 -#define DOT11_MNG_CHANNEL_SWITCH_ID 37 -#define DOT11_MNG_MEASURE_REQUEST_ID 38 -#define DOT11_MNG_MEASURE_REPORT_ID 39 -#define DOT11_MNG_QUIET_ID 40 -#define DOT11_MNG_IBSS_DFS_ID 41 -#define DOT11_MNG_ERP_ID 42 -#define DOT11_MNG_TS_DELAY_ID 43 -#define DOT11_MNG_HT_CAP 45 -#define DOT11_MNG_QOS_CAP_ID 46 -#define DOT11_MNG_NONERP_ID 47 -#define DOT11_MNG_RSN_ID 48 -#define DOT11_MNG_EXT_RATES_ID 50 -#define DOT11_MNG_REGCLASS_ID 59 -#define DOT11_MNG_EXT_CSA_ID 60 -#define DOT11_MNG_HT_ADD 61 -#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 -#ifdef BCMWAPI_WPI -#define DOT11_MNG_WAPI_ID 68 -#endif -#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 -#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 -#define DOT11_MNG_HT_OBSS_ID 74 -#define DOT11_MNG_EXT_CAP 127 -#define DOT11_MNG_WPA_ID 221 -#define DOT11_MNG_PROPR_ID 221 +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 +#define DOT11_ADDBA_POLICY_DELAYED 0 +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 -#define DOT11_RATE_BASIC 0x80 -#define DOT11_RATE_MASK 0x7F +BWL_PRE_PACKED_STRUCT struct dot11_addba_req { + uint8 category; + uint8 action; + uint8 token; + uint16 addba_param_set; + uint16 timeout; + uint16 start_seqnum; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 + +BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { + uint8 category; + uint8 action; + uint8 token; + uint16 status; + uint16 addba_param_set; + uint16 timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 -#define DOT11_MNG_ERP_LEN 1 -#define DOT11_MNG_NONERP_PRESENT 0x01 -#define DOT11_MNG_USE_PROTECTION 0x02 -#define DOT11_MNG_BARKER_PREAMBLE 0x04 +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 +#define DOT11_DELBA_PARAM_TID_SHIFT 12 -#define DOT11_MGN_TS_DELAY_LEN 4 -#define TS_DELAY_FIELD_SIZE 4 +BWL_PRE_PACKED_STRUCT struct dot11_delba { + uint8 category; + uint8 action; + uint16 delba_param_set; + uint16 reason; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 -#define DOT11_CAP_ESS 0x0001 -#define DOT11_CAP_IBSS 0x0002 -#define DOT11_CAP_POLLABLE 0x0004 -#define DOT11_CAP_POLL_RQ 0x0008 -#define DOT11_CAP_PRIVACY 0x0010 -#define DOT11_CAP_SHORT 0x0020 -#define DOT11_CAP_PBCC 0x0040 -#define DOT11_CAP_AGILITY 0x0080 -#define DOT11_CAP_SPECTRUM 0x0100 -#define DOT11_CAP_SHORTSLOT 0x0400 -#define DOT11_CAP_CCK_OFDM 0x2000 -#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 +#define DOT11_RRM_CAP_LEN 5 +BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { + uint8 cap[DOT11_RRM_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; -#define DOT11_ACTION_HDR_LEN 2 -#define DOT11_ACTION_CAT_ERR_MASK 0x80 -#define DOT11_ACTION_CAT_MASK 0x7F -#define DOT11_ACTION_CAT_SPECT_MNG 0 -#define DOT11_ACTION_CAT_BLOCKACK 3 -#define DOT11_ACTION_CAT_PUBLIC 4 -#define DOT11_ACTION_CAT_HT 7 -#define DOT11_ACTION_CAT_VS 127 -#define DOT11_ACTION_NOTIFICATION 0x11 -#define DOT11_ACTION_ID_M_REQ 0 -#define DOT11_ACTION_ID_M_REP 1 -#define DOT11_ACTION_ID_TPC_REQ 2 -#define DOT11_ACTION_ID_TPC_REP 3 -#define DOT11_ACTION_ID_CHANNEL_SWITCH 4 -#define DOT11_ACTION_ID_EXT_CSA 5 +#define DOT11_RRM_CAP_LINK 0 +#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 +#define DOT11_RRM_CAP_PARALLEL 2 +#define DOT11_RRM_CAP_REPEATED 3 +#define DOT11_RRM_CAP_BCN_PASSIVE 4 +#define DOT11_RRM_CAP_BCN_ACTIVE 5 +#define DOT11_RRM_CAP_BCN_TABLE 6 +#define DOT11_RRM_CAP_BCN_REP_COND 7 +#define DOT11_RRM_CAP_AP_CHANREP 16 -#define DOT11_ACTION_ID_HT_CH_WIDTH 0 -#define DOT11_ACTION_ID_HT_MIMO_PS 1 +#define DOT11_RM_ACTION_RM_REQ 0 +#define DOT11_RM_ACTION_RM_REP 1 +#define DOT11_RM_ACTION_LM_REQ 2 +#define DOT11_RM_ACTION_LM_REP 3 +#define DOT11_RM_ACTION_NR_REQ 4 +#define DOT11_RM_ACTION_NR_REP 5 -#define DOT11_ACTION_ID_BSS_COEX_MNG 0 +BWL_PRE_PACKED_STRUCT struct dot11_rm_action { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_action dot11_rm_action_t; +#define DOT11_RM_ACTION_LEN 3 + +BWL_PRE_PACKED_STRUCT struct dot11_rmreq { + uint8 category; + uint8 action; + uint8 token; + uint16 reps; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq dot11_rmreq_t; +#define DOT11_RMREQ_LEN 5 +BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rm_ie dot11_rm_ie_t; +#define DOT11_RM_IE_LEN 5 -#define DOT11_BA_ACTION_ADDBA_REQ 0 -#define DOT11_BA_ACTION_ADDBA_RESP 1 -#define DOT11_BA_ACTION_DELBA 2 +#define DOT11_RMREQ_MODE_PARALLEL 1 +#define DOT11_RMREQ_MODE_ENABLE 2 +#define DOT11_RMREQ_MODE_REQUEST 4 +#define DOT11_RMREQ_MODE_REPORT 8 +#define DOT11_RMREQ_MODE_DURMAND 0x10 -#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 -#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 -#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 -#define DOT11_ADDBA_PARAM_TID_MASK 0x003c -#define DOT11_ADDBA_PARAM_TID_SHIFT 2 -#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 -#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 -#define DOT11_ADDBA_POLICY_DELAYED 0 -#define DOT11_ADDBA_POLICY_IMMEDIATE 1 +#define DOT11_RMREP_MODE_LATE 1 +#define DOT11_RMREP_MODE_INCAPABLE 2 +#define DOT11_RMREP_MODE_REFUSED 4 -BWL_PRE_PACKED_STRUCT struct dot11_addba_req { - uint8 category; - uint8 action; - uint8 token; - uint16 addba_param_set; - uint16 timeout; - uint16 start_seqnum; -}BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_req dot11_addba_req_t; -#define DOT11_ADDBA_REQ_LEN 9 +BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 reg; + uint8 channel; + uint16 interval; + uint16 duration; + uint8 bcn_mode; + struct ether_addr bssid; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; +#define DOT11_RMREQ_BCN_LEN 18 -BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { - uint8 category; - uint8 action; - uint8 token; - uint16 status; - uint16 addba_param_set; - uint16 timeout; -}BWL_POST_PACKED_STRUCT; -typedef struct dot11_addba_resp dot11_addba_resp_t; -#define DOT11_ADDBA_RESP_LEN 9 +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { + uint8 reg; + uint8 channel; + uint32 starttime[2]; + uint16 duration; + uint8 frame_info; + uint8 rcpi; + uint8 rsni; + struct ether_addr bssid; + uint8 antenna_id; + uint32 parent_tsf; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; +#define DOT11_RMREP_BCN_LEN 26 -#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 -#define DOT11_DELBA_PARAM_INIT_SHIFT 11 -#define DOT11_DELBA_PARAM_TID_MASK 0xf000 -#define DOT11_DELBA_PARAM_TID_SHIFT 12 +#define DOT11_RMREQ_BCN_PASSIVE 0 +#define DOT11_RMREQ_BCN_ACTIVE 1 +#define DOT11_RMREQ_BCN_TABLE 2 -BWL_PRE_PACKED_STRUCT struct dot11_delba { - uint8 category; - uint8 action; - uint16 delba_param_set; - uint16 reason; -}BWL_POST_PACKED_STRUCT; -typedef struct dot11_delba dot11_delba_t; -#define DOT11_DELBA_LEN 6 +#define DOT11_RMREQ_BCN_SSID_ID 0 +#define DOT11_RMREQ_BCN_REPINFO_ID 1 +#define DOT11_RMREQ_BCN_REPDET_ID 2 +#define DOT11_RMREQ_BCN_REQUEST_ID 10 +#define DOT11_RMREQ_BCN_APCHREP_ID 51 -#define DOT11_BSSTYPE_INFRASTRUCTURE 0 -#define DOT11_BSSTYPE_INDEPENDENT 1 -#define DOT11_BSSTYPE_ANY 2 -#define DOT11_SCANTYPE_ACTIVE 0 -#define DOT11_SCANTYPE_PASSIVE 1 +#define DOT11_RMREQ_BCN_REPDET_FIXED 0 +#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 +#define DOT11_RMREQ_BCN_REPDET_ALL 2 -#define PREN_PREAMBLE 24 -#define PREN_MM_EXT 8 -#define PREN_PREAMBLE_EXT 4 +#define DOT11_RMREP_BCN_FRM_BODY 1 -#define NPHY_RIFS_TIME 2 +BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { + struct ether_addr bssid; + uint32 bssid_info; + uint8 reg; + uint8 channel; + uint8 phytype; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; +#define DOT11_RMREP_NBR_LEN 13 -#define APHY_SLOT_TIME 9 -#define APHY_SIFS_TIME 16 -#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) -#define APHY_PREAMBLE_TIME 16 -#define APHY_SIGNAL_TIME 4 -#define APHY_SYMBOL_TIME 4 -#define APHY_SERVICE_NBITS 16 -#define APHY_TAIL_NBITS 6 -#define APHY_CWMIN 15 +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 +#define DOT11_BSSTYPE_INDEPENDENT 1 +#define DOT11_BSSTYPE_ANY 2 +#define DOT11_SCANTYPE_ACTIVE 0 +#define DOT11_SCANTYPE_PASSIVE 1 -#define BPHY_SLOT_TIME 20 -#define BPHY_SIFS_TIME 10 -#define BPHY_DIFS_TIME 50 -#define BPHY_PLCP_TIME 192 -#define BPHY_PLCP_SHORT_TIME 96 -#define BPHY_CWMIN 31 +BWL_PRE_PACKED_STRUCT struct dot11_lmreq { + uint8 category; + uint8 action; + uint8 token; + uint8 txpwr; + uint8 maxtxpwr; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmreq dot11_lmreq_t; +#define DOT11_LMREQ_LEN 5 + +BWL_PRE_PACKED_STRUCT struct dot11_lmrep { + uint8 category; + uint8 action; + uint8 token; + dot11_tpc_rep_t tpc; + uint8 rxant; + uint8 txant; + uint8 rcpi; + uint8 rsni; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_lmrep dot11_lmrep_t; +#define DOT11_LMREP_LEN 11 -#define DOT11_OFDM_SIGNAL_EXTENSION 6 -#define PHY_CWMAX 1023 +#define PREN_PREAMBLE 24 +#define PREN_MM_EXT 12 +#define PREN_PREAMBLE_EXT 4 -#define DOT11_MAXNUMFRAGS 16 +#define RIFS_11N_TIME 2 -typedef struct d11cnt { - uint32 txfrag; - uint32 txmulti; - uint32 txfail; - uint32 txretry; - uint32 txretrie; - uint32 rxdup; - uint32 txrts; - uint32 txnocts; - uint32 txnoack; - uint32 rxfrag; - uint32 rxmulti; - uint32 rxcrc; - uint32 txfrmsnt; - uint32 rxundec; -} d11cnt_t; -#define BRCM_PROP_OUI "\x00\x90\x4C" +#define HT_SIG1_MCS_MASK 0x00007F +#define HT_SIG1_CBW 0x000080 +#define HT_SIG1_HT_LENGTH 0xFFFF00 +#define HT_SIG2_SMOOTHING 0x000001 +#define HT_SIG2_NOT_SOUNDING 0x000002 +#define HT_SIG2_RESERVED 0x000004 +#define HT_SIG2_AGGREGATION 0x000008 +#define HT_SIG2_STBC_MASK 0x000030 +#define HT_SIG2_STBC_SHIFT 4 +#define HT_SIG2_FEC_CODING 0x000040 +#define HT_SIG2_SHORT_GI 0x000080 +#define HT_SIG2_ESS_MASK 0x000300 +#define HT_SIG2_ESS_SHIFT 8 +#define HT_SIG2_CRC 0x03FC00 +#define HT_SIG2_TAIL 0x1C0000 -BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; - uint16 cap; -} BWL_POST_PACKED_STRUCT; -typedef struct brcm_prop_ie_s brcm_prop_ie_t; +#define APHY_SLOT_TIME 9 +#define APHY_SIFS_TIME 16 +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) +#define APHY_PREAMBLE_TIME 16 +#define APHY_SIGNAL_TIME 4 +#define APHY_SYMBOL_TIME 4 +#define APHY_SERVICE_NBITS 16 +#define APHY_TAIL_NBITS 6 +#define APHY_CWMIN 15 + + +#define BPHY_SLOT_TIME 20 +#define BPHY_SIFS_TIME 10 +#define BPHY_DIFS_TIME 50 +#define BPHY_PLCP_TIME 192 +#define BPHY_PLCP_SHORT_TIME 96 +#define BPHY_CWMIN 31 + + +#define DOT11_OFDM_SIGNAL_EXTENSION 6 + +#define PHY_CWMAX 1023 + +#define DOT11_MAXNUMFRAGS 16 -#define BRCM_PROP_IE_LEN 6 -#define DPT_IE_TYPE 2 +typedef struct d11cnt { + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 txretry; + uint32 txretrie; + uint32 rxdup; + uint32 txrts; + uint32 txnocts; + uint32 txnoack; + uint32 rxfrag; + uint32 rxmulti; + uint32 rxcrc; + uint32 txfrmsnt; + uint32 rxundec; +} d11cnt_t; + + +#define BRCM_PROP_OUI "\x00\x90\x4C" -#define BRCM_OUI "\x00\x10\x18" + +#define BRCM_OUI "\x00\x10\x18" BWL_PRE_PACKED_STRUCT struct brcm_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 ver; - uint8 assoc; - uint8 flags; - uint8 flags1; - uint16 amsdu_mtu_pref; + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 ver; + uint8 assoc; + uint8 flags; + uint8 flags1; + uint16 amsdu_mtu_pref; } BWL_POST_PACKED_STRUCT; -typedef struct brcm_ie brcm_ie_t; -#define BRCM_IE_LEN 11 -#define BRCM_IE_VER 2 -#define BRCM_IE_LEGACY_AES_VER 1 +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 +#define BRCM_IE_VER 2 +#define BRCM_IE_LEGACY_AES_VER 1 #ifdef WLAFTERBURNER -#define BRF_ABCAP 0x1 -#define BRF_ABRQRD 0x2 -#define BRF_ABCOUNTER_MASK 0xf0 -#define BRF_ABCOUNTER_SHIFT 4 +#define BRF_ABCAP 0x1 +#define BRF_ABRQRD 0x2 +#define BRF_ABCOUNTER_MASK 0xf0 +#define BRF_ABCOUNTER_SHIFT 4 #endif -#define BRF_LZWDS 0x4 -#define BRF_BLOCKACK 0x8 +#define BRF_LZWDS 0x4 +#define BRF_BLOCKACK 0x8 -#define BRF1_AMSDU 0x1 -#define BRF1_WMEPS 0x4 -#define BRF1_PSOFIX 0x8 +#define BRF1_AMSDU 0x1 +#define BRF1_WMEPS 0x4 +#define BRF1_PSOFIX 0x8 +#define BRF1_RX_LARGE_AGG 0x10 +#define BRF1_SOFTAP 0x40 #ifdef WLAFTERBURNER -#define AB_WDS_TIMEOUT_MAX 15 -#define AB_WDS_TIMEOUT_MIN 1 -#endif +#define AB_WDS_TIMEOUT_MAX 15 +#define AB_WDS_TIMEOUT_MIN 1 +#endif + +#define AB_GUARDCOUNT 10 + + +BWL_PRE_PACKED_STRUCT struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; +} BWL_POST_PACKED_STRUCT; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 +#define VNDR_IE_MIN_LEN 3 +#define VNDR_IE_MAX_LEN 256 -#define AB_GUARDCOUNT 10 -#define MCSSET_LEN 16 -#define MAX_MCS_NUM (128) +#define MCSSET_LEN 16 +#define MAX_MCS_NUM (128) BWL_PRE_PACKED_STRUCT struct ht_cap_ie { - uint16 cap; - uint8 params; - uint8 supp_mcs[MCSSET_LEN]; - uint16 ext_htcap; - uint32 txbf_cap; - uint8 as_cap; + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; } BWL_POST_PACKED_STRUCT; typedef struct ht_cap_ie ht_cap_ie_t; BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; ht_cap_ie_t cap_ie; } BWL_POST_PACKED_STRUCT; typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; -#define HT_PROP_IE_OVERHEAD 4 -#define HT_CAP_IE_LEN 26 -#define HT_CAP_IE_TYPE 51 - -#define HT_CAP_LDPC_CODING 0x0001 -#define HT_CAP_40MHZ 0x0002 -#define HT_CAP_MIMO_PS_MASK 0x000C -#define HT_CAP_MIMO_PS_SHIFT 0x0002 -#define HT_CAP_MIMO_PS_OFF 0x0003 -#define HT_CAP_MIMO_PS_RTS 0x0001 -#define HT_CAP_MIMO_PS_ON 0x0000 -#define HT_CAP_GF 0x0010 -#define HT_CAP_SHORT_GI_20 0x0020 -#define HT_CAP_SHORT_GI_40 0x0040 -#define HT_CAP_TX_STBC 0x0080 -#define HT_CAP_RX_STBC_MASK 0x0300 -#define HT_CAP_RX_STBC_SHIFT 8 -#define HT_CAP_DELAYED_BA 0x0400 -#define HT_CAP_MAX_AMSDU 0x0800 -#define HT_CAP_DSSS_CCK 0x1000 -#define HT_CAP_PSMP 0x2000 -#define HT_CAP_40MHZ_INTOLERANT 0x4000 -#define HT_CAP_LSIG_TXOP 0x8000 - -#define HT_CAP_RX_STBC_NO 0x0 -#define HT_CAP_RX_STBC_ONE_STREAM 0x1 -#define HT_CAP_RX_STBC_TWO_STREAM 0x2 -#define HT_CAP_RX_STBC_THREE_STREAM 0x3 - -#define HT_MAX_AMSDU 7935 -#define HT_MIN_AMSDU 3835 - -#define HT_PARAMS_RX_FACTOR_MASK 0x03 -#define HT_PARAMS_DENSITY_MASK 0x1C -#define HT_PARAMS_DENSITY_SHIFT 2 - - -#define AMPDU_MAX_MPDU_DENSITY 7 -#define AMPDU_RX_FACTOR_64K 3 -#define AMPDU_RX_FACTOR_BASE 8*1024 -#define AMPDU_DELIMITER_LEN 4 + +#define HT_PROP_IE_OVERHEAD 4 +#define HT_CAP_IE_LEN 26 +#define HT_CAP_IE_TYPE 51 + +#define HT_CAP_LDPC_CODING 0x0001 +#define HT_CAP_40MHZ 0x0002 +#define HT_CAP_MIMO_PS_MASK 0x000C +#define HT_CAP_MIMO_PS_SHIFT 0x0002 +#define HT_CAP_MIMO_PS_OFF 0x0003 +#define HT_CAP_MIMO_PS_RTS 0x0001 +#define HT_CAP_MIMO_PS_ON 0x0000 +#define HT_CAP_GF 0x0010 +#define HT_CAP_SHORT_GI_20 0x0020 +#define HT_CAP_SHORT_GI_40 0x0040 +#define HT_CAP_TX_STBC 0x0080 +#define HT_CAP_RX_STBC_MASK 0x0300 +#define HT_CAP_RX_STBC_SHIFT 8 +#define HT_CAP_DELAYED_BA 0x0400 +#define HT_CAP_MAX_AMSDU 0x0800 +#define HT_CAP_DSSS_CCK 0x1000 +#define HT_CAP_PSMP 0x2000 +#define HT_CAP_40MHZ_INTOLERANT 0x4000 +#define HT_CAP_LSIG_TXOP 0x8000 + +#define HT_CAP_RX_STBC_NO 0x0 +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 +#define HT_CAP_RX_STBC_TWO_STREAM 0x2 +#define HT_CAP_RX_STBC_THREE_STREAM 0x3 + +#define HT_MAX_AMSDU 7935 +#define HT_MIN_AMSDU 3835 + +#define HT_PARAMS_RX_FACTOR_MASK 0x03 +#define HT_PARAMS_DENSITY_MASK 0x1C +#define HT_PARAMS_DENSITY_SHIFT 2 + + +#define AMPDU_MAX_MPDU_DENSITY 7 +#define AMPDU_RX_FACTOR_8K 0 +#define AMPDU_RX_FACTOR_16K 1 +#define AMPDU_RX_FACTOR_32K 2 +#define AMPDU_RX_FACTOR_64K 3 +#define AMPDU_RX_FACTOR_BASE 8*1024 + +#define AMPDU_DELIMITER_LEN 4 +#define AMPDU_DELIMITER_LEN_MAX 63 BWL_PRE_PACKED_STRUCT struct ht_add_ie { - uint8 ctl_ch; - uint8 byte1; - uint16 opmode; - uint16 misc_bits; - uint8 basic_mcs[MCSSET_LEN]; + uint8 ctl_ch; + uint8 byte1; + uint16 opmode; + uint16 misc_bits; + uint8 basic_mcs[MCSSET_LEN]; } BWL_POST_PACKED_STRUCT; typedef struct ht_add_ie ht_add_ie_t; BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { - uint8 id; - uint8 len; - uint8 oui[3]; - uint8 type; + uint8 id; + uint8 len; + uint8 oui[3]; + uint8 type; ht_add_ie_t add_ie; } BWL_POST_PACKED_STRUCT; typedef struct ht_prop_add_ie ht_prop_add_ie_t; -#define HT_ADD_IE_LEN 22 -#define HT_ADD_IE_TYPE 52 +#define HT_ADD_IE_LEN 22 +#define HT_ADD_IE_TYPE 52 -#define HT_BW_ANY 0x04 -#define HT_RIFS_PERMITTED 0x08 +#define HT_BW_ANY 0x04 +#define HT_RIFS_PERMITTED 0x08 -#define HT_OPMODE_MASK 0x0003 -#define HT_OPMODE_SHIFT 0 -#define HT_OPMODE_PURE 0x0000 -#define HT_OPMODE_OPTIONAL 0x0001 -#define HT_OPMODE_HT20IN40 0x0002 -#define HT_OPMODE_MIXED 0x0003 -#define HT_OPMODE_NONGF 0x0004 -#define DOT11N_TXBURST 0x0008 -#define DOT11N_OBSS_NONHT 0x0010 +#define HT_OPMODE_MASK 0x0003 +#define HT_OPMODE_SHIFT 0 +#define HT_OPMODE_PURE 0x0000 +#define HT_OPMODE_OPTIONAL 0x0001 +#define HT_OPMODE_HT20IN40 0x0002 +#define HT_OPMODE_MIXED 0x0003 +#define HT_OPMODE_NONGF 0x0004 +#define DOT11N_TXBURST 0x0008 +#define DOT11N_OBSS_NONHT 0x0010 -#define HT_BASIC_STBC_MCS 0x007f -#define HT_DUAL_STBC_PROT 0x0080 -#define HT_SECOND_BCN 0x0100 -#define HT_LSIG_TXOP 0x0200 -#define HT_PCO_ACTIVE 0x0400 -#define HT_PCO_PHASE 0x0800 -#define HT_DUALCTS_PROTECTION 0x0080 +#define HT_BASIC_STBC_MCS 0x007f +#define HT_DUAL_STBC_PROT 0x0080 +#define HT_SECOND_BCN 0x0100 +#define HT_LSIG_TXOP 0x0200 +#define HT_PCO_ACTIVE 0x0400 +#define HT_PCO_PHASE 0x0800 -#define DOT11N_2G_TXBURST_LIMIT 6160 -#define DOT11N_5G_TXBURST_LIMIT 3080 +#define DOT11N_2G_TXBURST_LIMIT 6160 +#define DOT11N_5G_TXBURST_LIMIT 3080 -#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ +#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ >> HT_OPMODE_SHIFT) -#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_MIXED) -#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_HT20IN40) -#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ - == HT_OPMODE_OPTIONAL) -#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ +#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_MIXED) +#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_HT20IN40) +#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ + == HT_OPMODE_OPTIONAL) +#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ HT_MIXEDMODE_PRESENT((add_ie))) -#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ - == HT_OPMODE_NONGF) -#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ - == DOT11N_TXBURST) -#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ - == DOT11N_OBSS_NONHT) +#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ + == HT_OPMODE_NONGF) +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) BWL_PRE_PACKED_STRUCT struct obss_params { - uint16 passive_dwell; - uint16 active_dwell; - uint16 bss_widthscan_interval; - uint16 passive_total; - uint16 active_total; - uint16 chanwidth_transition_dly; - uint16 activity_threshold; + uint16 passive_dwell; + uint16 active_dwell; + uint16 bss_widthscan_interval; + uint16 passive_total; + uint16 active_total; + uint16 chanwidth_transition_dly; + uint16 activity_threshold; } BWL_POST_PACKED_STRUCT; typedef struct obss_params obss_params_t; BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { - uint8 id; - uint8 len; + uint8 id; + uint8 len; obss_params_t obss_params; } BWL_POST_PACKED_STRUCT; typedef struct dot11_obss_ie dot11_obss_ie_t; -#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) +#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) + + +#define HT_CTRL_LA_TRQ 0x00000002 +#define HT_CTRL_LA_MAI 0x0000003C +#define HT_CTRL_LA_MAI_SHIFT 2 +#define HT_CTRL_LA_MAI_MRQ 0x00000004 +#define HT_CTRL_LA_MAI_MSI 0x00000038 +#define HT_CTRL_LA_MFSI 0x000001C0 +#define HT_CTRL_LA_MFSI_SHIFT 6 +#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 +#define HT_CTRL_LA_MFB_ASELC_SH 9 +#define HT_CTRL_LA_ASELC_CMD 0x00000C00 +#define HT_CTRL_LA_ASELC_DATA 0x0000F000 +#define HT_CTRL_CAL_POS 0x00030000 +#define HT_CTRL_CAL_SEQ 0x000C0000 +#define HT_CTRL_CSI_STEERING 0x00C00000 +#define HT_CTRL_CSI_STEER_SHIFT 22 +#define HT_CTRL_CSI_STEER_NFB 0 +#define HT_CTRL_CSI_STEER_CSI 1 +#define HT_CTRL_CSI_STEER_NCOM 2 +#define HT_CTRL_CSI_STEER_COM 3 +#define HT_CTRL_NDP_ANNOUNCE 0x01000000 +#define HT_CTRL_AC_CONSTRAINT 0x40000000 +#define HT_CTRL_RDG_MOREPPDU 0x80000000 + +#define HT_OPMODE_OPTIONAL 0x0001 +#define HT_OPMODE_HT20IN40 0x0002 +#define HT_OPMODE_MIXED 0x0003 +#define HT_OPMODE_NONGF 0x0004 +#define DOT11N_TXBURST 0x0008 +#define DOT11N_OBSS_NONHT 0x0010 + + + +#define WPA_OUI "\x00\x50\xF2" +#define WPA_OUI_LEN 3 +#define WPA_OUI_TYPE 1 +#define WPA_VERSION 1 +#define WPA2_OUI "\x00\x0F\xAC" +#define WPA2_OUI_LEN 3 +#define WPA2_VERSION 1 +#define WPA2_VERSION_LEN 2 + + +#define WPS_OUI "\x00\x50\xF2" +#define WPS_OUI_LEN 3 +#define WPS_OUI_TYPE 4 + + +#define WFA_OUI "\x50\x6F\x9A" +#define WFA_OUI_LEN 3 + +#define WFA_OUI_TYPE_WPA 1 +#define WFA_OUI_TYPE_WPS 4 +#define WFA_OUI_TYPE_TPC 8 +#define WFA_OUI_TYPE_P2P 9 + + +#define RSN_AKM_NONE 0 +#define RSN_AKM_UNSPECIFIED 1 +#define RSN_AKM_PSK 2 +#define RSN_AKM_FBT_1X 3 +#define RSN_AKM_FBT_PSK 4 + + +#define DOT11_MAX_DEFAULT_KEYS 4 +#define DOT11_MAX_KEY_SIZE 32 +#define DOT11_MAX_IV_SIZE 16 +#define DOT11_EXT_IV_FLAG (1<<5) +#define DOT11_WPA_KEY_RSC_LEN 8 +#define WEP1_KEY_SIZE 5 +#define WEP1_KEY_HEX_SIZE 10 +#define WEP128_KEY_SIZE 13 +#define WEP128_KEY_HEX_SIZE 26 +#define TKIP_MIC_SIZE 8 +#define TKIP_EOM_SIZE 7 +#define TKIP_EOM_FLAG 0x5a +#define TKIP_KEY_SIZE 32 +#define TKIP_MIC_AUTH_TX 16 +#define TKIP_MIC_AUTH_RX 24 +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX +#define AES_KEY_SIZE 16 +#define AES_MIC_SIZE 8 -BWL_PRE_PACKED_STRUCT struct vndr_ie { - uchar id; - uchar len; - uchar oui [3]; - uchar data [1]; -} BWL_POST_PACKED_STRUCT; -typedef struct vndr_ie vndr_ie_t; -#define VNDR_IE_HDR_LEN 2 -#define VNDR_IE_MIN_LEN 3 -#define VNDR_IE_MAX_LEN 256 +#define WCN_OUI "\x00\x50\xf2" +#define WCN_TYPE 4 + -#define WPA_VERSION 1 -#define WPA_OUI "\x00\x50\xF2" -#define WPA2_VERSION 1 -#define WPA2_VERSION_LEN 2 -#define WPA2_OUI "\x00\x0F\xAC" -#define WPA_OUI_LEN 3 +BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { + uint8 id; + uint8 len; + uint16 mdid; + uint8 cap; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_mdid_ie dot11_mdid_ie_t; +#define FBT_MDID_CAP_OVERDS 0x01 +#define FBT_MDID_CAP_RRP 0x02 -#define RSN_AKM_NONE 0 -#define RSN_AKM_UNSPECIFIED 1 -#define RSN_AKM_PSK 2 +BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { + uint8 id; + uint8 len; + uint16 mic_control; + uint8 mic[16]; + uint8 anonce[32]; + uint8 snonce[32]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_ie dot11_ft_ie_t; -#define DOT11_MAX_DEFAULT_KEYS 4 -#define DOT11_MAX_KEY_SIZE 32 -#define DOT11_MAX_IV_SIZE 16 -#define DOT11_EXT_IV_FLAG (1<<5) -#define DOT11_WPA_KEY_RSC_LEN 8 -#define WEP1_KEY_SIZE 5 -#define WEP1_KEY_HEX_SIZE 10 -#define WEP128_KEY_SIZE 13 -#define WEP128_KEY_HEX_SIZE 26 -#define TKIP_MIC_SIZE 8 -#define TKIP_EOM_SIZE 7 -#define TKIP_EOM_FLAG 0x5a -#define TKIP_KEY_SIZE 32 -#define TKIP_MIC_AUTH_TX 16 -#define TKIP_MIC_AUTH_RX 24 -#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX -#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX -#define AES_KEY_SIZE 16 -#define AES_MIC_SIZE 8 - -#ifdef BCMWAPI_WPI -#define SMS4_KEY_LEN 16 -#define SMS4_WPI_CBC_MAC_LEN 16 -#endif +BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { + uint8 id; + uint8 len; + uint16 key_info; + uint8 key_len; + uint8 rsc[8]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_gtk_ie dot11_gtk_ie_t; + #include <packed_section_end.h> diff --git a/src/include/proto/802.11_bta.h b/src/include/proto/802.11_bta.h new file mode 100644 index 0000000..4ccfab0 --- /dev/null +++ b/src/include/proto/802.11_bta.h @@ -0,0 +1,45 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: 802.11_bta.h,v 9.2 2008-10-28 23:27:13 Exp $ +*/ + +#ifndef _802_11_BTA_H_ +#define _802_11_BTA_H_ + +#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" + +/* BT-AMP 802.11 PAL Protocols */ +#define BTA_PROT_L2CAP 1 +#define BTA_PROT_ACTIVITY_REPORT 2 +#define BTA_PROT_SECURITY 3 +#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 +#define BTA_PROT_LINK_SUPERVISION_REPLY 5 + +/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ +#define BTA_TYPE_ID_MAC_ADDRESS 1 +#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 +#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 +#define BTA_TYPE_ID_CAPABILITIES 4 +#define BTA_TYPE_ID_VERSION 5 +#endif /* _802_11_bta_h_ */ diff --git a/src/include/proto/802.11e.h b/src/include/proto/802.11e.h index ae46532..ce8ad08 100644 --- a/src/include/proto/802.11e.h +++ b/src/include/proto/802.11e.h @@ -1,7 +1,7 @@ /* * 802.11e protocol header file * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: 802.11e.h,v 1.5.92.1 2008/10/25 00:31:22 Exp $ + * $Id: 802.11e.h,v 1.6 2008-12-01 22:55:11 Exp $ */ #ifndef _802_11e_H_ diff --git a/src/include/proto/802.1d.h b/src/include/proto/802.1d.h index ea1f3df..cf20625 100644 --- a/src/include/proto/802.1d.h +++ b/src/include/proto/802.1d.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.1D * - * $Id: 802.1d.h,v 9.3 2007/04/10 21:33:06 Exp $ + * $Id: 802.1d.h,v 9.3 2007-04-10 21:33:06 Exp $ */ diff --git a/src/include/proto/bcmeth.h b/src/include/proto/bcmeth.h index 5860a15..46fa4c9 100644 --- a/src/include/proto/bcmeth.h +++ b/src/include/proto/bcmeth.h @@ -1,7 +1,7 @@ /* * Broadcom Ethernettype protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: bcmeth.h,v 9.9.70.1 2008/10/25 00:31:24 Exp $ + * $Id: bcmeth.h,v 9.12 2009-12-29 19:57:18 Exp $ */ diff --git a/src/include/proto/bcmevent.h b/src/include/proto/bcmevent.h index 3883b34..7f51faa 100644 --- a/src/include/proto/bcmevent.h +++ b/src/include/proto/bcmevent.h @@ -1,7 +1,7 @@ /* * Broadcom Event protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,10 +21,9 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * * Dependencies: proto/bcmeth.h * - * $Id: bcmevent.h,v 9.34.4.1.2.3.2.8 2009/09/29 16:26:40 Exp $ + * $Id: bcmevent.h,v 9.64.2.9 2011-02-01 06:24:21 Exp $ * */ @@ -41,13 +40,17 @@ #include <packed_section_start.h> -#define BCM_EVENT_MSG_VERSION 1 +#define BCM_EVENT_MSG_VERSION 2 #define BCM_MSG_IFNAME_MAX 16 #define WLC_EVENT_MSG_LINK 0x01 #define WLC_EVENT_MSG_FLUSHTXQ 0x02 #define WLC_EVENT_MSG_GROUP 0x04 +#define WLC_EVENT_MSG_UNKBSS 0x08 +#define WLC_EVENT_MSG_UNKIF 0x10 + + typedef BWL_PRE_PACKED_STRUCT struct @@ -61,6 +64,22 @@ typedef BWL_PRE_PACKED_STRUCT struct uint32 datalen; struct ether_addr addr; char ifname[BCM_MSG_IFNAME_MAX]; +} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; + + +typedef BWL_PRE_PACKED_STRUCT struct +{ + uint16 version; + uint16 flags; + uint32 event_type; + uint32 status; + uint32 reason; + uint32 auth_type; + uint32 datalen; + struct ether_addr addr; + char ifname[BCM_MSG_IFNAME_MAX]; + uint8 ifidx; + uint8 bsscfgidx; } BWL_POST_PACKED_STRUCT wl_event_msg_t; @@ -118,21 +137,60 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_PSM_WATCHDOG 41 #define WLC_E_PROBREQ_MSG 44 #define WLC_E_SCAN_CONFIRM_IND 45 -#define WLC_E_PSK_SUP 46 +#define WLC_E_PSK_SUP 46 #define WLC_E_COUNTRY_CODE_CHANGED 47 #define WLC_E_EXCEEDED_MEDIUM_TIME 48 #define WLC_E_ICV_ERROR 49 -#define WLC_E_UNICAST_DECODE_ERROR 50 +#define WLC_E_UNICAST_DECODE_ERROR 50 #define WLC_E_MULTICAST_DECODE_ERROR 51 -#define WLC_E_TRACE 52 +#define WLC_E_TRACE 52 +#define WLC_E_BTA_HCI_EVENT 53 #define WLC_E_IF 54 +#ifdef WLP2P +#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 +#endif #define WLC_E_RSSI 56 #define WLC_E_PFN_SCAN_COMPLETE 57 -#define WLC_E_ACTION_FRAME 58 -#define WLC_E_ACTION_FRAME_COMPLETE 59 -#define WLC_E_ESCAN_RESULT 69 -#define WLC_E_LAST 70 +#define WLC_E_EXTLOG_MSG 58 +#define WLC_E_ACTION_FRAME 59 +#define WLC_E_ACTION_FRAME_COMPLETE 60 +#define WLC_E_PRE_ASSOC_IND 61 +#define WLC_E_PRE_REASSOC_IND 62 +#define WLC_E_CHANNEL_ADOPTED 63 +#define WLC_E_AP_STARTED 64 +#define WLC_E_DFS_AP_STOP 65 +#define WLC_E_DFS_AP_RESUME 66 +#define WLC_E_WAI_STA_EVENT 67 +#define WLC_E_WAI_MSG 68 +#define WLC_E_ESCAN_RESULT 69 +#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 +#if defined(WLP2P) +#define WLC_E_PROBRESP_MSG 71 +#define WLC_E_P2P_PROBREQ_MSG 72 +#endif +#define WLC_E_DCS_REQUEST 73 + +#define WLC_E_FIFO_CREDIT_MAP 74 + +#define WLC_E_ACTION_FRAME_RX 75 +#define WLC_E_WAKE_EVENT 76 +#define WLC_E_RM_COMPLETE 77 +#define WLC_E_HTSFSYNC 78 +#define WLC_E_OVERLAY_REQ 79 +#define WLC_E_CSA_COMPLETE_IND 80 +#define WLC_E_EXCESS_PM_WAKE_EVENT 81 +#define WLC_E_PFN_SCAN_NONE 82 +#define WLC_E_PFN_SCAN_ALLGONE 83 +#define WLC_E_LAST 84 + + +typedef struct { + uint event; + const char *name; +} bcmevent_name_t; +extern const bcmevent_name_t bcmevent_names[]; +extern const int bcmevent_names_size; #define WLC_E_STATUS_SUCCESS 0 @@ -144,13 +202,13 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_STATUS_UNSOLICITED 6 #define WLC_E_STATUS_ATTEMPT 7 #define WLC_E_STATUS_PARTIAL 8 -#define WLC_E_STATUS_NEWSCAN 9 -#define WLC_E_STATUS_NEWASSOC 10 -#define WLC_E_STATUS_11HQUIET 11 -#define WLC_E_STATUS_SUPPRESS 12 -#define WLC_E_STATUS_NOCHANS 13 -#define WLC_E_STATUS_CCXFASTRM 14 -#define WLC_E_STATUS_CS_ABORT 15 +#define WLC_E_STATUS_NEWSCAN 9 +#define WLC_E_STATUS_NEWASSOC 10 +#define WLC_E_STATUS_11HQUIET 11 +#define WLC_E_STATUS_SUPPRESS 12 +#define WLC_E_STATUS_NOCHANS 13 +#define WLC_E_STATUS_CS_ABORT 15 +#define WLC_E_STATUS_ERROR 16 #define WLC_E_REASON_INITIAL_ASSOC 0 @@ -161,6 +219,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_REASON_MINTXRATE 9 #define WLC_E_REASON_TXFAIL 10 + #define WLC_E_REASON_FAST_ROAM_FAILED 5 #define WLC_E_REASON_DIRECTED_ROAM 6 #define WLC_E_REASON_TSPEC_REJECTED 7 @@ -184,7 +243,7 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_PRUNE_HOME_AP 17 -#define WLC_E_SUP_OTHER 0 +#define WLC_E_SUP_OTHER 0 #define WLC_E_SUP_DECRYPT_KEY_DATA 1 #define WLC_E_SUP_BAD_UCAST_WEP128 2 #define WLC_E_SUP_BAD_UCAST_WEP40 3 @@ -197,13 +256,44 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_SUP_GRP_KEY_CIPHER 10 #define WLC_E_SUP_GRP_MSG1_NO_GTK 11 #define WLC_E_SUP_GTK_DECRYPT_FAIL 12 -#define WLC_E_SUP_SEND_FAIL 13 -#define WLC_E_SUP_DEAUTH 14 -#define WLC_E_SUP_WPA_PSK_TMO 15 +#define WLC_E_SUP_SEND_FAIL 13 +#define WLC_E_SUP_DEAUTH 14 +#define WLC_E_SUP_WPA_PSK_TMO 15 + + + +typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { + uint16 version; + uint16 channel; + int32 rssi; + uint32 mactime; + uint32 rate; +} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; + +#define BCM_RX_FRAME_DATA_VERSION 1 + + +typedef struct wl_event_data_if { + uint8 ifidx; + uint8 opcode; + uint8 reserved; + uint8 bssidx; + uint8 role; +} wl_event_data_if_t; #define WLC_E_IF_ADD 1 #define WLC_E_IF_DEL 2 +#define WLC_E_IF_CHANGE 3 + + +#define WLC_E_IF_ROLE_STA 0 +#define WLC_E_IF_ROLE_AP 1 +#define WLC_E_IF_ROLE_WDS 2 +#define WLC_E_IF_ROLE_P2P_GO 3 +#define WLC_E_IF_ROLE_P2P_CLIENT 4 +#define WLC_E_IF_ROLE_BTA_CREATOR 5 +#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 #define WLC_E_LINK_BCN_LOSS 1 @@ -212,6 +302,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_LINK_BSSCFG_DIS 4 +#define WLC_E_OVL_DOWNLOAD 0 +#define WLC_E_OVL_UPDATE_IND 1 + + #include <packed_section_end.h> #endif diff --git a/src/include/proto/bcmip.h b/src/include/proto/bcmip.h index cbe9a90..8a8f314 100644 --- a/src/include/proto/bcmip.h +++ b/src/include/proto/bcmip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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 constants relating to IP Protocol * - * $Id: bcmip.h,v 9.16.230.2 2008/11/10 21:39:35 Exp $ + * $Id: bcmip.h,v 9.19 2009-11-10 20:08:33 Exp $ */ @@ -144,12 +144,9 @@ BWL_PRE_PACKED_STRUCT struct ipv4_hdr { #define IPV6_ADDR_LEN 16 -#ifndef IP_TOS -#define IP_TOS(ip_body) \ +#define IP_TOS46(ip_body) \ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) -#endif - #include <packed_section_end.h> diff --git a/src/include/proto/bt_amp_hci.h b/src/include/proto/bt_amp_hci.h new file mode 100644 index 0000000..89c1181 --- /dev/null +++ b/src/include/proto/bt_amp_hci.h @@ -0,0 +1,442 @@ +/* + * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: bt_amp_hci.h,v 9.14.8.2 2010-09-10 18:37:47 Exp $ +*/ + +#ifndef _bt_amp_hci_h +#define _bt_amp_hci_h + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + + +/* AMP HCI CMD packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { + uint16 opcode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; + +#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) +#define HCI_CMD_DATA_SIZE 255 + +/* AMP HCI CMD opcode layout */ +#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) +#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) +#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) + +/* AMP HCI command opcodes */ +#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) +#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) +#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) +#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) +#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) +#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) +#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) +#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) +#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) +#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) +#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) +#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) +#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) +#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) +#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) +#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) +#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) +#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) +#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) +#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) +#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) +#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) +#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) +#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) +#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) +#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) +#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) +#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) +#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) +#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) +#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) +#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) +#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) + +/* AMP HCI command parameters */ +typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { + uint8 plh; + uint8 offset[2]; /* length so far */ + uint8 max_remote[2]; +} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { + uint8 plh; + uint8 offset[2]; + uint8 len[2]; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { + uint8 plh; + uint8 key_length; + uint8 key_type; + uint8 key[1]; +} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { + uint8 plh; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { + uint8 id; + uint8 service_type; + uint8 max_sdu[2]; + uint8 sdu_ia_time[4]; + uint8 access_latency[4]; + uint8 flush_timeout[4]; +} BWL_POST_PACKED_STRUCT ext_flow_spec_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { + uint8 llh[2]; + uint8 txflow[16]; + uint8 rxflow[16]; +} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct plh_pad { + uint8 plh; + uint8 pad; +} BWL_POST_PACKED_STRUCT plh_pad_t; + +typedef BWL_PRE_PACKED_STRUCT union hci_handle { + uint16 bredr; + plh_pad_t amp; +} BWL_POST_PACKED_STRUCT hci_handle_t; + +typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { + hci_handle_t handle; + uint8 timeout[2]; +} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { + uint8 llh[2]; + uint8 befto[4]; +} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { + uint8 llh[2]; + uint8 packet_type; +} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; + +/* Generic AMP extended flow spec service types */ +#define EFS_SVCTYPE_NO_TRAFFIC 0 +#define EFS_SVCTYPE_BEST_EFFORT 1 +#define EFS_SVCTYPE_GUARANTEED 2 + +/* AMP HCI event packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { + uint8 ecode; + uint8 plen; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT amp_hci_event_t; + +#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) + +/* AMP HCI event codes */ +#define HCI_Command_Complete 0x0E +#define HCI_Command_Status 0x0F +#define HCI_Flush_Occurred 0x11 +#define HCI_Enhanced_Flush_Complete 0x39 +#define HCI_Physical_Link_Complete 0x40 +#define HCI_Channel_Select 0x41 +#define HCI_Disconnect_Physical_Link_Complete 0x42 +#define HCI_Logical_Link_Complete 0x45 +#define HCI_Disconnect_Logical_Link_Complete 0x46 +#define HCI_Flow_Spec_Modify_Complete 0x47 +#define HCI_Number_of_Completed_Data_Blocks 0x48 +#define HCI_Short_Range_Mode_Change_Complete 0x4C +#define HCI_Status_Change_Event 0x4D +#define HCI_Vendor_Specific 0xFF + +/* AMP HCI event mask bit positions */ +#define HCI_Physical_Link_Complete_Event_Mask 0x0001 +#define HCI_Channel_Select_Event_Mask 0x0002 +#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 +#define HCI_Logical_Link_Complete_Event_Mask 0x0020 +#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 +#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 +#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 +#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 +#define HCI_Status_Change_Event_Mask 0x2000 +#define HCI_All_Event_Mask 0x31e7 + +/* AMP HCI event parameters */ +typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { + uint8 status; + uint8 cmdpkts; + uint16 opcode; +} BWL_POST_PACKED_STRUCT cmd_status_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { + uint8 cmdpkts; + uint16 opcode; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { + uint8 status; + uint8 plh; + uint16 len; + uint8 frag[1]; +} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { + uint8 status; + uint8 AMP_status; + uint32 bandwidth; + uint32 gbandwidth; + uint32 latency; + uint32 PDU_size; + uint8 ctrl_type; + uint16 PAL_cap; + uint16 AMP_ASSOC_len; + uint32 max_flush_timeout; + uint32 be_flush_timeout; +} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { + uint8 status; + uint16 llh; + uint8 reason; +} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { + uint8 status; + uint8 plh; + uint8 tx_fs_ID; +} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { + uint8 status; + uint16 llh; +} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { + uint8 status; + uint8 plh; +} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { + uint8 status; + uint8 plh; + uint8 reason; +} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { + uint8 status; + hci_handle_t handle; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { + uint8 status; + uint16 timeout; +} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { + uint8 status; + uint16 ACL_pkt_len; + uint16 data_block_len; + uint16 data_block_num; +} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct data_blocks { + uint16 handle; + uint16 pkts; + uint16 blocks; +} BWL_POST_PACKED_STRUCT data_blocks_t; + +typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { + uint16 num_blocks; + uint8 num_handles; + data_blocks_t completed[1]; +} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { + uint8 status; + uint32 befto; +} BWL_POST_PACKED_STRUCT befto_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { + uint8 status; + uint8 plh; + uint8 srm; +} BWL_POST_PACKED_STRUCT srm_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { + uint8 status; + uint8 llh[2]; + uint16 counter; +} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { + uint8 status; + uint8 llh[2]; +} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { + uint8 status; + hci_handle_t handle; + uint8 link_quality; +} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { + uint8 status; + uint8 ld_aware; + uint8 ld[2]; + uint8 ld_opts; + uint8 l_opts; +} BWL_POST_PACKED_STRUCT ld_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { + uint16 handle; +} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { + uint8 len; + uint8 parms[1]; +} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { + uint8 status; + uint8 hci_version; + uint16 hci_revision; + uint8 pal_version; + uint16 mfg_name; + uint16 pal_subversion; +} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; + +#define MAX_SUPPORTED_CMD_BYTE 64 +typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { + uint8 status; + uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; +} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; + +typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { + uint8 status; + uint8 amp_status; +} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; + +/* AMP HCI error codes */ +#define HCI_SUCCESS 0x00 +#define HCI_ERR_ILLEGAL_COMMAND 0x01 +#define HCI_ERR_NO_CONNECTION 0x02 +#define HCI_ERR_MEMORY_FULL 0x07 +#define HCI_ERR_CONNECTION_TIMEOUT 0x08 +#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 +#define HCI_ERR_CONNECTION_EXISTS 0x0B +#define HCI_ERR_CONNECTION_DISALLOWED 0x0C +#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 +#define HCI_ERR_UNSUPPORTED_VALUE 0x11 +#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 +#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 +#define HCI_ERR_UNSPECIFIED 0x1F +#define HCI_ERR_UNIT_KEY_USED 0x26 +#define HCI_ERR_QOS_REJECTED 0x2D +#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 +#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 +#define HCI_ERR_CHANNEL_MOVE 0xFF + +/* AMP HCI ACL Data packet format */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { + uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ + uint16 dlen; /* data total length */ + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; + +#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) + +#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) +#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) + +#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) +#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) + +/* AMP Activity Report packet formats */ +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { + uint8 ScheduleKnown; + uint8 NumReports; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; + +typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { + uint32 StartTime; + uint32 Duration; + uint32 Periodicity; +} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; + +#define HCI_AR_SCHEDULE_KNOWN 0x01 + + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _bt_amp_hci_h_ */ diff --git a/src/include/proto/eapol.h b/src/include/proto/eapol.h index ec65229..5781d13 100644 --- a/src/include/proto/eapol.h +++ b/src/include/proto/eapol.h @@ -7,7 +7,7 @@ * * Copyright (C) 2002 Broadcom Corporation * - * $Id: eapol.h,v 9.18.260.1.2.1.20.6 2009/04/08 05:01:46 Exp $ + * $Id: eapol.h,v 9.23.86.1 2010-09-02 18:09:39 Exp $ */ #ifndef _eapol_h_ @@ -20,7 +20,7 @@ /* This marks the start of a packed structure section. */ #include <packed_section_start.h> -#define AKW_BLOCK_LEN 8 /* The only def we need here */ +#include <bcmcrypto/aeskeywrap.h> /* EAPOL for 802.3/Ethernet */ typedef struct { @@ -81,8 +81,8 @@ typedef BWL_PRE_PACKED_STRUCT struct { #define EAPOL_WPA_KEY_REPLAY_LEN 8 #define EAPOL_WPA_KEY_NONCE_LEN 32 #define EAPOL_WPA_KEY_IV_LEN 16 -#define EAPOL_WPA_KEY_ID_LEN 8 #define EAPOL_WPA_KEY_RSC_LEN 8 +#define EAPOL_WPA_KEY_ID_LEN 8 #define EAPOL_WPA_KEY_MIC_LEN 16 #define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) #define EAPOL_WPA_MAX_KEY_SIZE 32 @@ -107,6 +107,7 @@ typedef BWL_PRE_PACKED_STRUCT struct { /* WPA/802.11i/WPA2 KEY KEY_INFO bits */ #define WPA_KEY_DESC_V1 0x01 #define WPA_KEY_DESC_V2 0x02 +#define WPA_KEY_DESC_V3 0x03 #define WPA_KEY_PAIRWISE 0x08 #define WPA_KEY_INSTALL 0x40 #define WPA_KEY_ACK 0x80 diff --git a/src/include/proto/ethernet.h b/src/include/proto/ethernet.h index b68be58..6a6dd14 100644 --- a/src/include/proto/ethernet.h +++ b/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-2011, 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.74.2 2009/06/25 14:46:22 Exp $ + * $Id: ethernet.h,v 9.56 2009-10-15 22:54:58 Exp $ */ @@ -67,12 +67,9 @@ #define ETHER_TYPE_8021Q 0x8100 #define ETHER_TYPE_BRCM 0x886c #define ETHER_TYPE_802_1X 0x888e -#ifdef BCMWAPI_WPI -#define ETHER_TYPE_WAI 0x88b4 -#endif -#ifdef BCMWPA2 #define ETHER_TYPE_802_1X_PREAUTH 0x88c7 -#endif +#define ETHER_TYPE_WAI 0x88b4 + #define ETHER_BRCM_SUBTYPE_LEN 4 @@ -87,6 +84,14 @@ #define ETHER_IS_VALID_LEN(foo) \ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) +#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ + ((uint8 *)ea)[0] = 0x01; \ + ((uint8 *)ea)[1] = 0x00; \ + ((uint8 *)ea)[2] = 0x5e; \ + ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ + ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ + ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ +} #ifndef __INCif_etherh @@ -127,24 +132,29 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { ((short*)d)[2] = ((short*)s)[2]; } -#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ - ((uint8 *)(ea))[1] & \ - ((uint8 *)(ea))[2] & \ - ((uint8 *)(ea))[3] & \ - ((uint8 *)(ea))[4] & \ - ((uint8 *)(ea))[5]) == 0xff) - static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; - -#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ - ((uint8 *)(ea))[1] | \ - ((uint8 *)(ea))[2] | \ - ((uint8 *)(ea))[3] | \ - ((uint8 *)(ea))[4] | \ - ((uint8 *)(ea))[5]) == 0) - +#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ + ((uint8 *)(ea))[1] & \ + ((uint8 *)(ea))[2] & \ + ((uint8 *)(ea))[3] & \ + ((uint8 *)(ea))[4] & \ + ((uint8 *)(ea))[5]) == 0xff) +#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ + ((uint8 *)(ea))[1] | \ + ((uint8 *)(ea))[2] | \ + ((uint8 *)(ea))[3] | \ + ((uint8 *)(ea))[4] | \ + ((uint8 *)(ea))[5]) == 0) + + +#define ETHER_MOVE_HDR(d, s) \ +do { \ + struct ether_header t; \ + t = *(struct ether_header *)(s); \ + *(struct ether_header *)(d) = t; \ +} while (0) #include <packed_section_end.h> diff --git a/src/include/proto/p2p.h b/src/include/proto/p2p.h new file mode 100644 index 0000000..4a0c9d1 --- /dev/null +++ b/src/include/proto/p2p.h @@ -0,0 +1,512 @@ +/* + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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. + * + * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) + * + * $Id: p2p.h,v 9.17.2.4 2010-12-15 21:41:21 Exp $ + */ + +#ifndef _P2P_H_ +#define _P2P_H_ + +#ifndef _TYPEDEFS_H_ +#include <typedefs.h> +#endif +#include <wlioctl.h> +#include <proto/802.11.h> + +/* This marks the start of a packed structure section. */ +#include <packed_section_start.h> + + +/* WiFi P2P OUI values */ +#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ +#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ + +#define P2P_IE_ID 0xdd /* P2P IE element ID */ + +/* WiFi P2P IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { + uint8 id; /* IE ID: 0xDD */ + uint8 len; /* IE length */ + uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ + uint8 oui_type; /* Identifies P2P version: P2P_VER */ + uint8 subelts[1]; /* variable length subelements */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ie wifi_p2p_ie_t; + +#define P2P_IE_FIXED_LEN 6 + +#define P2P_ATTR_ID_OFF 0 +#define P2P_ATTR_LEN_OFF 1 +#define P2P_ATTR_DATA_OFF 3 + +#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ + +/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ +#define P2P_SEID_STATUS 0 /* Status */ +#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ +#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ +#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ +#define P2P_SEID_INTENT 4 /* Group Owner Intent */ +#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ +#define P2P_SEID_CHANNEL 6 /* Channel */ +#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ +#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ +#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ +#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ +#define P2P_SEID_CHAN_LIST 11 /* Channel List */ +#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ +#define P2P_SEID_DEV_INFO 13 /* Device Info */ +#define P2P_SEID_GROUP_INFO 14 /* Group Info */ +#define P2P_SEID_GROUP_ID 15 /* Group ID */ +#define P2P_SEID_P2P_IF 16 /* P2P Interface */ +#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ + +#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM proprietary subel: L2 Services */ + + +/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 dev; /* Device Capability Bitmap */ + uint8 group; /* Group Capability Bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; + +/* P2P Capability subelement's Device Capability Bitmap bit values */ +#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ +#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ +#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ +#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ +#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ +#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ + +/* P2P Capability subelement's Group Capability Bitmap bit values */ +#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ +#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ +#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ +#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ +#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ +#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ +#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ + + +/* WiFi P2P IE subelement: Group Owner Intent */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTENT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; + +/* WiFi P2P IE subelement: Configuration Timeout */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 go_tmo; /* GO config timeout in units of 10 ms */ + uint8 client_tmo; /* Client config timeout in units of 10 ms */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; + + +/* WiFi P2P IE subelement: Status */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 status; /* Status Code: P2P_STATSE_* */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; + +/* Status subelement Status Code definitions */ +#define P2P_STATSE_SUCCESS 0 + /* Success */ +#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 + /* Failed, information currently unavailable */ +#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL + /* Old name for above in P2P spec 1.08 and older */ +#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 + /* Failed, incompatible parameters */ +#define P2P_STATSE_FAIL_LIMIT_REACHED 3 + /* Failed, limit reached */ +#define P2P_STATSE_FAIL_INVALID_PARAMS 4 + /* Failed, invalid parameters */ +#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 + /* Failed, unable to accomodate request */ +#define P2P_STATSE_FAIL_PROTO_ERROR 6 + /* Failed, previous protocol error or disruptive behaviour */ +#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 + /* Failed, no common channels */ +#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 + /* Failed, unknown P2P Group */ +#define P2P_STATSE_FAIL_INTENT 9 + /* Failed, both peers indicated Intent 15 in GO Negotiation */ +#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 + /* Failed, incompatible provisioning method */ +#define P2P_STATSE_FAIL_USER_REJECT 11 + /* Failed, rejected by user */ + +/* WiFi P2P IE attribute: Extended Listen Timing */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { + uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ + uint8 len[2]; /* length not including eltId, len fields */ + uint8 avail[2]; /* availibility period */ + uint8 interval[2]; /* availibility interval */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; + +#define P2P_EXT_MIN 10 /* minimum 10ms */ + +/* WiFi P2P IE subelement: Intended P2P Interface Address */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { + uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* intended P2P interface MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; + +/* WiFi P2P IE subelement: Channel */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 band; /* Regulatory Class (band) */ + uint8 channel; /* Channel */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; + + +/* Channel Entry structure within the Channel List SE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { + uint8 band; /* Regulatory Class (band) */ + uint8 num_channels; /* # of channels in the channel list */ + uint8 channels[WL_NUMCHANNELS]; /* Channel List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; +#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 + +/* WiFi P2P IE subelement: Channel List */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { + uint8 eltId; /* SE ID: P2P_SEID_STATUS */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 country[3]; /* Country String */ + uint8 num_entries; /* # of channel entries */ + wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; + /* Channel Entry List */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; + +/* WiFi P2P IE's Device Info subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mac[6]; /* P2P Device MAC address */ + uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pri_devtype[8]; /* Primary Device Type */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; + +#define P2P_DEV_TYPE_LEN 8 + +/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { + uint8 len; + uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ + uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ + uint8 devcap; /* Device Capability */ + uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ + uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ + uint8 secdts; /* Number of Secondary Device Types */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; + +/* WiFi P2P IE's Device ID subelement */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { + uint8 eltId; + uint8 len[2]; + struct ether_addr addr; /* P2P Device MAC address */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; + +/* WiFi P2P IE subelement: P2P Manageability */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { + uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ + uint8 len[2]; /* SE length not including eltId, len fields */ + uint8 mg_bitmap; /* manageability bitmap */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; +/* mg_bitmap field bit values */ +#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ + +/* WiFi P2P IE subelement: Group Info */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { + uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ + uint8 len[2]; /* SE length not including eltId, len fields */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; + + +/* WiFi P2P Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { + uint8 category; /* P2P_AF_CATEGORY */ + uint8 OUI[3]; /* OUI - P2P_OUI */ + uint8 type; /* OUI Type - P2P_VER */ + uint8 subtype; /* OUI Subtype - P2P_AF_* */ + uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; +#define P2P_AF_CATEGORY 0x7f + +#define P2P_AF_FIXED_LEN 7 + +/* WiFi P2P Action Frame OUI Subtypes */ +#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ +#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ +#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ +#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ + + +/* WiFi P2P Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { + uint8 category; /* P2P_PUB_AF_CATEGORY */ + uint8 action; /* P2P_PUB_AF_ACTION */ + uint8 oui[3]; /* P2P_OUI */ + uint8 oui_type; /* OUI type - P2P_VER */ + uint8 subtype; /* OUI subtype - P2P_TYPE_* */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 elts[1]; /* Variable length information elements. Max size = + * ACTION_FRAME_SIZE - sizeof(this structure) - 1 + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; +#define P2P_PUB_AF_FIXED_LEN 8 +#define P2P_PUB_AF_CATEGORY 0x04 +#define P2P_PUB_AF_ACTION 0x09 + +/* WiFi P2P Public Action Frame OUI Subtypes */ +#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ +#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ +#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ +#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ +#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ +#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ +#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ +#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ +#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Request */ + +/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ +#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ +#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP +#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF + +/* WiFi P2P IE subelement: Notice of Absence */ +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { + uint8 cnt_type; /* Count/Type */ + uint32 duration; /* Duration */ + uint32 interval; /* Interval */ + uint32 start; /* Start Time */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; + +BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { + uint8 eltId; /* Subelement ID */ + uint8 len[2]; /* Length */ + uint8 index; /* Index */ + uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ + wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; + +#define P2P_NOA_SE_FIXED_LEN 5 + +/* cnt_type field values */ +#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ +#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ +#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ +#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ + +/* ctw_ops_parms field values */ +#define P2P_NOA_CTW_MASK 0x7f +#define P2P_NOA_OPS_MASK 0x80 +#define P2P_NOA_OPS_SHIFT 7 + +#define P2P_CTW_MIN 10 /* minimum 10TU */ + +/* + * P2P Service Discovery related + */ +#define P2PSD_ACTION_CATEGORY 0x04 + /* Public action frame */ +#define P2PSD_ACTION_ID_GAS_IREQ 0x0a + /* Action value for GAS Initial Request AF */ +#define P2PSD_ACTION_ID_GAS_IRESP 0x0b + /* Action value for GAS Initial Response AF */ +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c + /* Action value for GAS Comback Request AF */ +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d + /* Action value for GAS Comback Response AF */ +#define P2PSD_AD_EID 0x6c + /* Advertisement Protocol IE ID */ +#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 + /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ +#define P2PSD_ADP_PROTO_ID 0x00 + /* Advertisement Protocol ID. Always 0 for P2P SD */ +#define P2PSD_GAS_OUI P2P_OUI + /* WFA OUI */ +#define P2PSD_GAS_OUI_SUBTYPE P2P_VER + /* OUI Subtype for GAS IE */ +#define P2PSD_GAS_NQP_INFOID 0xDDDD + /* NQP Query Info ID: 56797 */ +#define P2PSD_GAS_COMEBACKDEALY 0x00 + /* Not used in the Native GAS protocol */ + +/* Service Protocol Type */ +typedef enum p2psd_svc_protype { + SVC_RPOTYPE_ALL = 0, + SVC_RPOTYPE_BONJOUR = 1, + SVC_RPOTYPE_UPNP = 2, + SVC_RPOTYPE_WSD = 3, + SVC_RPOTYPE_VENDOR = 255 +} p2psd_svc_protype_t; + +/* Service Discovery response status code */ +typedef enum { + P2PSD_RESP_STATUS_SUCCESS = 0, + P2PSD_RESP_STATUS_PROTYPE_NA = 1, + P2PSD_RESP_STATUS_DATA_NA = 2, + P2PSD_RESP_STATUS_BAD_REQUEST = 3 +} p2psd_resp_status_t; + +/* Advertisement Protocol IE tuple field */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { + uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus + * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 + */ + uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; + +/* Advertisement Protocol IE */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { + uint8 id; /* IE ID: 0x6c - 108 */ + uint8 len; /* IE length */ + wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one + * tuple is defined for P2P Service Discovery + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; + +/* NQP Vendor-specific Content */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { + uint8 oui_subtype; /* OUI Subtype: 0x09 */ + uint16 svc_updi; /* Service Update Indicator */ + uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, + * wifi_p2psd_qresp_tlv_t type for service response + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; + +/* Service Request TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; + +/* Query Request Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Length of service request TLV, 5 plus the size of request data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; + +/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qreq_len; /* Query Request Length */ + uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; + +/* Service Response TLV */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { + uint16 len; /* Length: 5 plus size of Query Data */ + uint8 svc_prot; /* Service Protocol Type */ + uint8 svc_tscid; /* Service Transaction ID */ + uint8 status; /* Value defined in Table 57 of P2P spec. */ + uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; + +/* Query Response Frame, defined in generic format, instead of NQP specific */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { + uint16 info_id; /* Info ID: 0xDDDD */ + uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ + uint8 oui[3]; /* WFA OUI: 0x0050F2 */ + uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ + +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; + +/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; + +/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { + uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ + uint8 fragment_id; /* Fragmentation ID */ + uint16 cb_delay; /* GAS Comeback Delay */ + wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ + uint16 qresp_len; /* Query Response Length */ + uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; + +/* Wi-Fi GAS Public Action Frame */ +BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { + uint8 category; /* 0x04 Public Action Frame */ + uint8 action; /* 0x6c Advertisement Protocol */ + uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ + uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t + * or wifi_p2psd_gas_iresp_frame_t format + */ +} BWL_POST_PACKED_STRUCT; +typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; + +/* This marks the end of a packed structure section. */ +#include <packed_section_end.h> + +#endif /* _P2P_H_ */ diff --git a/src/include/proto/sdspi.h b/src/include/proto/sdspi.h index d51ffcb..7fe4fbc 100644 --- a/src/include/proto/sdspi.h +++ b/src/include/proto/sdspi.h @@ -1,7 +1,7 @@ /* * SD-SPI Protocol Standard * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,9 +21,12 @@ * 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: sdspi.h,v 9.1.20.1 2008/05/06 22:59:19 Exp $ + * $Id: sdspi.h,v 9.2.120.1 2010-11-15 17:56:25 Exp $ */ +#ifndef _SD_SPI_H +#define _SD_SPI_H + #define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ #define SPI_START_S 31 #define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ @@ -69,3 +72,5 @@ #define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ #define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ #define SDSPI_START_BIT_MASK 0x80 + +#endif /* _SD_SPI_H */ diff --git a/src/include/proto/vlan.h b/src/include/proto/vlan.h index 15d13cf..07fa7e4 100644 --- a/src/include/proto/vlan.h +++ b/src/include/proto/vlan.h @@ -1,7 +1,7 @@ /* * 802.1Q VLAN protocol definitions * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: vlan.h,v 9.4.240.2 2008/12/07 21:15:40 Exp $ + * $Id: vlan.h,v 9.7 2009-03-13 01:11:50 Exp $ */ @@ -60,4 +60,11 @@ struct ethervlan_header { #include <packed_section_end.h> +#define ETHERVLAN_MOVE_HDR(d, s) \ +do { \ + struct ethervlan_header t; \ + t = *(struct ethervlan_header *)(s); \ + *(struct ethervlan_header *)(d) = t; \ +} while (0) + #endif diff --git a/src/include/proto/wpa.h b/src/include/proto/wpa.h index 08865b1..1ff06dc 100644 --- a/src/include/proto/wpa.h +++ b/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-2011, 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: wpa.h,v 1.16.166.1.34.1 2008/10/25 00:31:35 Exp $ + * $Id: wpa.h,v 1.19 2009-07-13 08:29:58 Exp $ */ @@ -115,6 +115,7 @@ typedef BWL_PRE_PACKED_STRUCT struct #define WPA_CIPHER_AES_CCM 4 #define WPA_CIPHER_WEP_104 5 + #define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ (cipher) == WPA_CIPHER_WEP_40 || \ (cipher) == WPA_CIPHER_WEP_104 || \ diff --git a/src/include/sbchipc.h b/src/include/sbchipc.h index 74bb173..cbd3749 100644 --- a/src/include/sbchipc.h +++ b/src/include/sbchipc.h @@ -2,12 +2,12 @@ * SiliconBackplane Chipcommon core hardware definitions. * * The chipcommon core provides chip identification, SB control, - * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer, - * gpio interface, extbus, and support for serial and parallel flashes. + * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, + * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h,v 13.103.2.5.4.7.4.1 2009/01/21 23:56:57 Exp $ + * $Id: sbchipc.h,v 13.169.2.14 2011-02-10 23:43:55 Exp $ * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -51,11 +51,13 @@ typedef volatile struct { uint32 otpstatus; uint32 otpcontrol; uint32 otpprog; - uint32 PAD; + uint32 otplayout; uint32 intstatus; uint32 intmask; + + uint32 chipcontrol; uint32 chipstatus; @@ -79,11 +81,11 @@ typedef volatile struct { uint32 gpiopullup; uint32 gpiopulldown; uint32 gpioin; - uint32 gpioout; - uint32 gpioouten; - uint32 gpiocontrol; - uint32 gpiointpolarity; - uint32 gpiointmask; + uint32 gpioout; + uint32 gpioouten; + uint32 gpiocontrol; + uint32 gpiointpolarity; + uint32 gpiointmask; uint32 gpioevent; @@ -106,21 +108,37 @@ typedef volatile struct { uint32 clockcontrol_m2; uint32 clockcontrol_m3; uint32 clkdiv; - uint32 PAD[2]; + uint32 gpiodebugsel; + uint32 capabilities_ext; uint32 pll_on_delay; uint32 fref_sel_delay; uint32 slow_clk_ctl; - uint32 PAD[1]; + uint32 PAD; uint32 system_clk_ctl; uint32 clkstatestretch; - uint32 PAD[13]; + uint32 PAD[2]; + + + uint32 bp_addrlow; + uint32 bp_addrhigh; + uint32 bp_data; + uint32 PAD; + uint32 bp_indaccess; + + uint32 gsioctrl; + uint32 gsioaddress; + uint32 gsiodata; + + + uint32 clkdiv2; + uint32 PAD[2]; - uint32 eromptr; + uint32 eromptr; uint32 pcmcia_config; @@ -138,7 +156,7 @@ typedef volatile struct { uint32 PAD[4]; uint32 PAD[40]; - + uint32 clk_ctl_st; uint32 hw_war; @@ -166,6 +184,7 @@ typedef volatile struct { uint32 PAD[126]; + uint32 pmucontrol; uint32 pmucapabilities; uint32 pmustatus; @@ -192,20 +211,34 @@ typedef volatile struct { uint32 regcontrol_data; uint32 pllcontrol_addr; uint32 pllcontrol_data; - uint32 PAD[102]; - uint16 otp[768]; + uint32 pmustrapopt; + uint32 pmu_xtalfreq; + uint32 PAD[100]; + uint16 sromotp[768]; } chipcregs_t; #endif + #define CC_CHIPID 0 #define CC_CAPABILITIES 4 +#define CC_CHIPST 0x2c +#define CC_EROMPTR 0xfc + + #define CC_OTPST 0x10 -#define CC_CHIPST 0x2c #define CC_JTAGCMD 0x30 #define CC_JTAGIR 0x34 #define CC_JTAGDR 0x38 #define CC_JTAGCTRL 0x3c +#define CC_GPIOPU 0x58 +#define CC_GPIOPD 0x5c +#define CC_GPIOIN 0x60 +#define CC_GPIOOUT 0x64 +#define CC_GPIOOUTEN 0x68 +#define CC_GPIOCTRL 0x6c +#define CC_GPIOPOL 0x70 +#define CC_GPIOINTM 0x74 #define CC_WATCHDOG 0x80 #define CC_CLKC_N 0x90 #define CC_CLKC_M0 0x94 @@ -215,7 +248,6 @@ typedef volatile struct { #define CC_CLKDIV 0xa4 #define CC_SYS_CLK_CTL 0xc0 #define CC_CLK_CTL_ST SI_CLK_CTL_ST -#define CC_EROMPTR 0xfc #define PMU_CTL 0x600 #define PMU_CAP 0x604 #define PMU_ST 0x608 @@ -223,11 +255,13 @@ typedef volatile struct { #define PMU_TIMER 0x614 #define PMU_MIN_RES_MASK 0x618 #define PMU_MAX_RES_MASK 0x61c +#define CC_CHIPCTL_ADDR 0x650 +#define CC_CHIPCTL_DATA 0x654 #define PMU_REG_CONTROL_ADDR 0x658 #define PMU_REG_CONTROL_DATA 0x65C #define PMU_PLL_CONTROL_ADDR 0x660 #define PMU_PLL_CONTROL_DATA 0x664 -#define CC_OTP 0x800 +#define CC_SROM_OTP 0x800 #define CID_ID_MASK 0x0000ffff @@ -261,6 +295,14 @@ typedef volatile struct { #define CC_CAP_BKPLN64 0x08000000 #define CC_CAP_PMU 0x10000000 #define CC_CAP_ECI 0x20000000 +#define CC_CAP_SROM 0x40000000 +#define CC_CAP_NFLASH 0x80000000 + +#define CC_CAP2_SECI 0x00000001 +#define CC_CAP2_GSIO 0x00000002 + + +#define CC_CAP_EXT_SECI_PRESENT 0x00000001 #define PLL_NONE 0x00000000 @@ -284,6 +326,7 @@ typedef volatile struct { #define CC_UARTCLKO 0x00000001 #define CC_SE 0x00000002 +#define CC_ASYNCGPIO 0x00000004 #define CC_UARTCLKEN 0x00000008 @@ -329,6 +372,10 @@ typedef volatile struct { #define OTPP_VALUE_MASK 0x20000000 #define OTPP_VALUE_SHIFT 29 #define OTPP_START_BUSY 0x80000000 +#define OTPP_READ 0x40000000 + + +#define OTP_CISFORMAT_NEW 0x80000000 #define OTPPOC_READ 0 @@ -342,6 +389,12 @@ typedef volatile struct { #define OTPPOC_PRESCN_TEST 9 + +#define JTAGM_CREV_OLD 10 +#define JTAGM_CREV_IRP 22 +#define JTAGM_CREV_RTI 28 + + #define JCMD_START 0x80000000 #define JCMD_BUSY 0x80000000 #define JCMD_STATE_MASK 0x60000000 @@ -385,6 +438,8 @@ typedef volatile struct { #define CLKD_JTAG_SHIFT 8 #define CLKD_UART 0x000000ff +#define CLKD2_SROM 0x00000003 + #define CI_GPIO 0x00000001 #define CI_EI 0x00000002 @@ -419,6 +474,17 @@ typedef volatile struct { #define SYCC_CD_SHIFT 16 +#define BPIA_BYTEEN 0x0000000f +#define BPIA_SZ1 0x00000001 +#define BPIA_SZ2 0x00000003 +#define BPIA_SZ4 0x00000007 +#define BPIA_SZ8 0x0000000f +#define BPIA_WRITE 0x00000100 +#define BPIA_START 0x00000200 +#define BPIA_BUSY 0x00000200 +#define BPIA_ERROR 0x00000400 + + #define CF_EN 0x00000001 #define CF_EM_MASK 0x0000000e #define CF_EM_SHIFT 1 @@ -486,8 +552,21 @@ typedef volatile struct { #define FW_W3_SHIFT 24 -#define WATCHDOG_CLOCK 48000000 -#define WATCHDOG_CLOCK_5354 32000 +#define SRC_START 0x80000000 +#define SRC_BUSY 0x80000000 +#define SRC_OPCODE 0x60000000 +#define SRC_OP_READ 0x00000000 +#define SRC_OP_WRITE 0x20000000 +#define SRC_OP_WRDIS 0x40000000 +#define SRC_OP_WREN 0x60000000 +#define SRC_OTPSEL 0x00000010 +#define SRC_LOCK 0x00000008 +#define SRC_SIZE_MASK 0x00000006 +#define SRC_SIZE_1K 0x00000000 +#define SRC_SIZE_4K 0x00000002 +#define SRC_SIZE_16K 0x00000004 +#define SRC_SIZE_SHIFT 1 +#define SRC_PRESENT 0x00000001 #define PCTL_ILP_DIV_MASK 0xffff0000 @@ -621,6 +700,7 @@ typedef volatile struct { #define SFLASH_ST_DP 0x00b9 #define SFLASH_ST_RES 0x03ab #define SFLASH_ST_CSA 0x1000 +#define SFLASH_ST_SSE 0x0220 #define SFLASH_ST_WIP 0x01 @@ -659,6 +739,10 @@ typedef volatile struct { #define SFLASH_AT_ID_SHIFT 3 +#define GSIO_START 0x80000000 +#define GSIO_BUSY GSIO_START + + #define UART_RX 0 #define UART_TX 0 @@ -703,6 +787,8 @@ typedef volatile struct { #define UART_IER_ERBFI 1 +#define PST_EXTLPOAVAIL 0x0100 +#define PST_WDRESET 0x0080 #define PST_INTPEND 0x0040 #define PST_SBCLKST 0x0030 #define PST_SBCLKST_ILP 0x0010 @@ -746,6 +832,32 @@ typedef volatile struct { #define PMURES_MAX_RESNUM 30 +#define PMU_CHIPCTL0 0 + + +#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 +#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) + +#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 +#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 + + +#define PMU_CHIPCTL1 1 +#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 + +#define PMU_CC1_IF_TYPE_MASK 0x00000030 +#define PMU_CC1_IF_TYPE_RMII 0x00000000 +#define PMU_CC1_IF_TYPE_MII 0x00000010 +#define PMU_CC1_IF_TYPE_RGMII 0x00000020 + +#define PMU_CC1_SW_TYPE_MASK 0x000000c0 +#define PMU_CC1_SW_TYPE_EPHY 0x00000000 +#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 +#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 +#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 + + + #define PMU0_PLL0_PLLCTL0 0 @@ -779,49 +891,6 @@ typedef volatile struct { #define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 -#define RES4328_EXT_SWITCHER_PWM 0 -#define RES4328_BB_SWITCHER_PWM 1 -#define RES4328_BB_SWITCHER_BURST 2 -#define RES4328_BB_EXT_SWITCHER_BURST 3 -#define RES4328_ILP_REQUEST 4 -#define RES4328_RADIO_SWITCHER_PWM 5 -#define RES4328_RADIO_SWITCHER_BURST 6 -#define RES4328_ROM_SWITCH 7 -#define RES4328_PA_REF_LDO 8 -#define RES4328_RADIO_LDO 9 -#define RES4328_AFE_LDO 10 -#define RES4328_PLL_LDO 11 -#define RES4328_BG_FILTBYP 12 -#define RES4328_TX_FILTBYP 13 -#define RES4328_RX_FILTBYP 14 -#define RES4328_XTAL_PU 15 -#define RES4328_XTAL_EN 16 -#define RES4328_BB_PLL_FILTBYP 17 -#define RES4328_RF_PLL_FILTBYP 18 -#define RES4328_BB_PLL_PU 19 - -#define RES5354_EXT_SWITCHER_PWM 0 -#define RES5354_BB_SWITCHER_PWM 1 -#define RES5354_BB_SWITCHER_BURST 2 -#define RES5354_BB_EXT_SWITCHER_BURST 3 -#define RES5354_ILP_REQUEST 4 -#define RES5354_RADIO_SWITCHER_PWM 5 -#define RES5354_RADIO_SWITCHER_BURST 6 -#define RES5354_ROM_SWITCH 7 -#define RES5354_PA_REF_LDO 8 -#define RES5354_RADIO_LDO 9 -#define RES5354_AFE_LDO 10 -#define RES5354_PLL_LDO 11 -#define RES5354_BG_FILTBYP 12 -#define RES5354_TX_FILTBYP 13 -#define RES5354_RX_FILTBYP 14 -#define RES5354_XTAL_PU 15 -#define RES5354_XTAL_EN 16 -#define RES5354_BB_PLL_FILTBYP 17 -#define RES5354_RF_PLL_FILTBYP 18 -#define RES5354_BB_PLL_PU 19 - - #define PMU1_PLL0_PLLCTL0 0 #define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 @@ -839,6 +908,9 @@ typedef volatile struct { #define PMU1_PLL0_PC1_M3DIV_SHIFT 16 #define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 #define PMU1_PLL0_PC1_M4DIV_SHIFT 24 +#define PMU1_PLL0_PC1_M4DIV_BY_9 9 +#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 +#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 #define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 #define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) @@ -848,10 +920,17 @@ typedef volatile struct { #define PMU1_PLL0_PLLCTL2 2 #define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff #define PMU1_PLL0_PC2_M5DIV_SHIFT 0 +#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc +#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 #define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 #define PMU1_PLL0_PC2_M6DIV_SHIFT 8 +#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 +#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 #define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 #define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 +#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 +#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 #define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 #define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 @@ -873,6 +952,181 @@ typedef volatile struct { #define PMU2_SI_PLL_PLLCTL 10 + + +#define PMU2_PLL_PLLCTL0 0 +#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 +#define PMU2_PLL_PC0_P1DIV_SHIFT 20 +#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 +#define PMU2_PLL_PC0_P2DIV_SHIFT 24 + + +#define PMU2_PLL_PLLCTL1 1 +#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff +#define PMU2_PLL_PC1_M1DIV_SHIFT 0 +#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC1_M2DIV_SHIFT 8 +#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 +#define PMU2_PLL_PC1_M3DIV_SHIFT 16 +#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 +#define PMU2_PLL_PC1_M4DIV_SHIFT 24 + + +#define PMU2_PLL_PLLCTL2 2 +#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff +#define PMU2_PLL_PC2_M5DIV_SHIFT 0 +#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 +#define PMU2_PLL_PC2_M6DIV_SHIFT 8 +#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 +#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 +#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 +#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 + + +#define PMU2_PLL_PLLCTL3 3 +#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff +#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 + + +#define PMU2_PLL_PLLCTL4 4 + + +#define PMU2_PLL_PLLCTL5 5 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 +#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 +#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 +#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 +#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 +#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 + + +#define PMU5_PLL_P1P2_OFF 0 +#define PMU5_PLL_P1_MASK 0x0f000000 +#define PMU5_PLL_P1_SHIFT 24 +#define PMU5_PLL_P2_MASK 0x00f00000 +#define PMU5_PLL_P2_SHIFT 20 +#define PMU5_PLL_M14_OFF 1 +#define PMU5_PLL_MDIV_MASK 0x000000ff +#define PMU5_PLL_MDIV_WIDTH 8 +#define PMU5_PLL_NM5_OFF 2 +#define PMU5_PLL_NDIV_MASK 0xfff00000 +#define PMU5_PLL_NDIV_SHIFT 20 +#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 +#define PMU5_PLL_NDIV_MODE_SHIFT 17 +#define PMU5_PLL_FMAB_OFF 3 +#define PMU5_PLL_MRAT_MASK 0xf0000000 +#define PMU5_PLL_MRAT_SHIFT 28 +#define PMU5_PLL_ABRAT_MASK 0x08000000 +#define PMU5_PLL_ABRAT_SHIFT 27 +#define PMU5_PLL_FDIV_MASK 0x07ffffff +#define PMU5_PLL_PLLCTL_OFF 4 +#define PMU5_PLL_PCHI_OFF 5 +#define PMU5_PLL_PCHI_MASK 0x0000003f + + +#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF +#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 +#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 + + +#define PMU5_MAINPLL_CPU 1 +#define PMU5_MAINPLL_MEM 2 +#define PMU5_MAINPLL_SI 3 + +#define PMU7_PLL_PLLCTL7 7 +#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 +#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 +#define PMU7_PLL_CTL7_M4DIV_BY_6 6 +#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc +#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL8 8 +#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff +#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 +#define PMU7_PLL_CTL8_M5DIV_BY_8 8 +#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 +#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 +#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 +#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc +#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 +#define PMU7_PLL_PLLCTL11 11 +#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 +#define PMU7_PLL_PLLCTL11_VAL 0x22222200 + + +#define PMU4716_MAINPLL_PLL0 12 + + +#define PMU5356_MAINPLL_PLL0 0 +#define PMU5357_MAINPLL_PLL0 0 + + +#define RES4716_PROC_PLL_ON 0x00000040 +#define RES4716_PROC_HT_AVAIL 0x00000080 + + +#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 + + + +#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 +#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 + + +#define RES5354_EXT_SWITCHER_PWM 0 +#define RES5354_BB_SWITCHER_PWM 1 +#define RES5354_BB_SWITCHER_BURST 2 +#define RES5354_BB_EXT_SWITCHER_BURST 3 +#define RES5354_ILP_REQUEST 4 +#define RES5354_RADIO_SWITCHER_PWM 5 +#define RES5354_RADIO_SWITCHER_BURST 6 +#define RES5354_ROM_SWITCH 7 +#define RES5354_PA_REF_LDO 8 +#define RES5354_RADIO_LDO 9 +#define RES5354_AFE_LDO 10 +#define RES5354_PLL_LDO 11 +#define RES5354_BG_FILTBYP 12 +#define RES5354_TX_FILTBYP 13 +#define RES5354_RX_FILTBYP 14 +#define RES5354_XTAL_PU 15 +#define RES5354_XTAL_EN 16 +#define RES5354_BB_PLL_FILTBYP 17 +#define RES5354_RF_PLL_FILTBYP 18 +#define RES5354_BB_PLL_PU 19 + + +#define CCTRL5357_EXTPA (1<<14) +#define CCTRL5357_ANT_MUX_2o3 (1<<15) + + +#define RES4328_EXT_SWITCHER_PWM 0 +#define RES4328_BB_SWITCHER_PWM 1 +#define RES4328_BB_SWITCHER_BURST 2 +#define RES4328_BB_EXT_SWITCHER_BURST 3 +#define RES4328_ILP_REQUEST 4 +#define RES4328_RADIO_SWITCHER_PWM 5 +#define RES4328_RADIO_SWITCHER_BURST 6 +#define RES4328_ROM_SWITCH 7 +#define RES4328_PA_REF_LDO 8 +#define RES4328_RADIO_LDO 9 +#define RES4328_AFE_LDO 10 +#define RES4328_PLL_LDO 11 +#define RES4328_BG_FILTBYP 12 +#define RES4328_TX_FILTBYP 13 +#define RES4328_RX_FILTBYP 14 +#define RES4328_XTAL_PU 15 +#define RES4328_XTAL_EN 16 +#define RES4328_BB_PLL_FILTBYP 17 +#define RES4328_RF_PLL_FILTBYP 18 +#define RES4328_BB_PLL_PU 19 + + #define RES4325_BUCK_BOOST_BURST 0 #define RES4325_CBUCK_BURST 1 #define RES4325_CBUCK_PWM 2 @@ -903,7 +1157,6 @@ typedef volatile struct { #define RES4325B0_CLDO_PU 4 -#define RES4325C1_OTP_PWRSW_PU 10 #define RES4325C1_LNLDO2_PU 12 @@ -953,6 +1206,13 @@ typedef volatile struct { #define CST4329_SPI_SDIO_MODE_SHIFT 2 +#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 +#define CST4312_DEFCIS_SEL 0 +#define CST4312_SPROM_SEL 1 +#define CST4312_OTP_SEL 2 +#define CST4312_OTP_BAD 3 + + #define RES4312_SWITCHER_BURST 0 #define RES4312_SWITCHER_PWM 1 #define RES4312_PA_REF_LDO 2 @@ -969,6 +1229,7 @@ typedef volatile struct { #define RES4312_RF_PLL_FILTBYP 13 #define RES4312_HT_AVAIL 14 + #define RES4322_RF_LDO 0 #define RES4322_ILP_REQUEST 1 #define RES4322_XTAL_PU 2 @@ -1009,6 +1270,88 @@ typedef volatile struct { #define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 #define CST4322_PCI_CARDBUS_MODE 0x00040000 + +#define CCTRL43224_GPIO_TOGGLE 0x8000 +#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 +#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 + + +#define RES43236_REGULATOR 0 +#define RES43236_ILP_REQUEST 1 +#define RES43236_XTAL_PU 2 +#define RES43236_ALP_AVAIL 3 +#define RES43236_SI_PLL_ON 4 +#define RES43236_HT_SI_AVAIL 5 + + +#define CCTRL43236_BT_COEXIST (1<<0) +#define CCTRL43236_SECI (1<<1) +#define CCTRL43236_EXT_LNA (1<<2) +#define CCTRL43236_ANT_MUX_2o3 (1<<3) +#define CCTRL43236_GSIO (1<<4) + + +#define CST43236_SFLASH_MASK 0x00000040 +#define CST43236_OTP_SEL_MASK 0x00000080 +#define CST43236_OTP_SEL_SHIFT 7 +#define CST43236_HSIC_MASK 0x00000100 +#define CST43236_BP_CLK 0x00000200 +#define CST43236_BOOT_MASK 0x00001800 +#define CST43236_BOOT_SHIFT 11 +#define CST43236_BOOT_FROM_SRAM 0 +#define CST43236_BOOT_FROM_ROM 1 +#define CST43236_BOOT_FROM_FLASH 2 +#define CST43236_BOOT_FROM_INVALID 3 + + +#define RES43237_REGULATOR 0 +#define RES43237_ILP_REQUEST 1 +#define RES43237_XTAL_PU 2 +#define RES43237_ALP_AVAIL 3 +#define RES43237_SI_PLL_ON 4 +#define RES43237_HT_SI_AVAIL 5 + + +#define CCTRL43237_BT_COEXIST (1<<0) +#define CCTRL43237_SECI (1<<1) +#define CCTRL43237_EXT_LNA (1<<2) +#define CCTRL43237_ANT_MUX_2o3 (1<<3) +#define CCTRL43237_GSIO (1<<4) + + +#define CST43237_SFLASH_MASK 0x00000040 +#define CST43237_OTP_SEL_MASK 0x00000080 +#define CST43237_OTP_SEL_SHIFT 7 +#define CST43237_HSIC_MASK 0x00000100 +#define CST43237_BP_CLK 0x00000200 +#define CST43237_BOOT_MASK 0x00001800 +#define CST43237_BOOT_SHIFT 11 +#define CST43237_BOOT_FROM_SRAM 0 +#define CST43237_BOOT_FROM_ROM 1 +#define CST43237_BOOT_FROM_FLASH 2 +#define CST43237_BOOT_FROM_INVALID 3 + + +#define RES43239_OTP_PU 9 +#define RES43239_MACPHY_CLKAVAIL 23 +#define RES43239_HT_AVAIL 24 + + +#define CST43239_SPROM_MASK 0x00000002 +#define CST43239_SFLASH_MASK 0x00000004 +#define CST43239_RES_INIT_MODE_SHIFT 7 +#define CST43239_RES_INIT_MODE_MASK 0x000001f0 +#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) +#define CST43239_CHIPMODE_USB20D(cs) ((cs) & !(1 << 15)) +#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) +#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) + + +#define CCTRL43239_XTAL_STRENGTH(ctl) ((ctl & 0x3F) << 12) + + + + #define RES4315_CBUCK_LPOM 1 #define RES4315_CBUCK_BURST 2 #define RES4315_CBUCK_PWM 3 @@ -1028,6 +1371,7 @@ typedef volatile struct { #define RES4315_BBPLL_PWRSW_PU 20 #define RES4315_HT_AVAIL 21 + #define CST4315_SPROM_OTP_SEL_MASK 0x00000003 #define CST4315_DEFCIS_SEL 0x00000000 #define CST4315_SPROM_SEL 0x00000001 @@ -1043,6 +1387,208 @@ typedef volatile struct { #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 RES4336_CBUCK_LPOM 0 +#define RES4336_CBUCK_BURST 1 +#define RES4336_CBUCK_LP_PWM 2 +#define RES4336_CBUCK_PWM 3 +#define RES4336_CLDO_PU 4 +#define RES4336_DIS_INT_RESET_PD 5 +#define RES4336_ILP_REQUEST 6 +#define RES4336_LNLDO_PU 7 +#define RES4336_LDO3P3_PU 8 +#define RES4336_OTP_PU 9 +#define RES4336_XTAL_PU 10 +#define RES4336_ALP_AVAIL 11 +#define RES4336_RADIO_PU 12 +#define RES4336_BG_PU 13 +#define RES4336_VREG1p4_PU_PU 14 +#define RES4336_AFE_PWRSW_PU 15 +#define RES4336_RX_PWRSW_PU 16 +#define RES4336_TX_PWRSW_PU 17 +#define RES4336_BB_PWRSW_PU 18 +#define RES4336_SYNTH_PWRSW_PU 19 +#define RES4336_MISC_PWRSW_PU 20 +#define RES4336_LOGEN_PWRSW_PU 21 +#define RES4336_BBPLL_PWRSW_PU 22 +#define RES4336_MACPHY_CLKAVAIL 23 +#define RES4336_HT_AVAIL 24 +#define RES4336_RSVD 25 + + +#define CST4336_SPI_MODE_MASK 0x00000001 +#define CST4336_SPROM_PRESENT 0x00000002 +#define CST4336_OTP_PRESENT 0x00000004 +#define CST4336_ARMREMAP_0 0x00000008 +#define CST4336_ILPDIV_EN_MASK 0x00000010 +#define CST4336_ILPDIV_EN_SHIFT 4 +#define CST4336_XTAL_PD_POL_MASK 0x00000020 +#define CST4336_XTAL_PD_POL_SHIFT 5 +#define CST4336_LPO_SEL_MASK 0x00000040 +#define CST4336_LPO_SEL_SHIFT 6 +#define CST4336_RES_INIT_MODE_MASK 0x00000180 +#define CST4336_RES_INIT_MODE_SHIFT 7 +#define CST4336_CBUCK_MODE_MASK 0x00000600 +#define CST4336_CBUCK_MODE_SHIFT 9 + + +#define PCTL_4336_SERIAL_ENAB (1 << 24) + + +#define RES4330_CBUCK_LPOM 0 +#define RES4330_CBUCK_BURST 1 +#define RES4330_CBUCK_LP_PWM 2 +#define RES4330_CBUCK_PWM 3 +#define RES4330_CLDO_PU 4 +#define RES4330_DIS_INT_RESET_PD 5 +#define RES4330_ILP_REQUEST 6 +#define RES4330_LNLDO_PU 7 +#define RES4330_LDO3P3_PU 8 +#define RES4330_OTP_PU 9 +#define RES4330_XTAL_PU 10 +#define RES4330_ALP_AVAIL 11 +#define RES4330_RADIO_PU 12 +#define RES4330_BG_PU 13 +#define RES4330_VREG1p4_PU_PU 14 +#define RES4330_AFE_PWRSW_PU 15 +#define RES4330_RX_PWRSW_PU 16 +#define RES4330_TX_PWRSW_PU 17 +#define RES4330_BB_PWRSW_PU 18 +#define RES4330_SYNTH_PWRSW_PU 19 +#define RES4330_MISC_PWRSW_PU 20 +#define RES4330_LOGEN_PWRSW_PU 21 +#define RES4330_BBPLL_PWRSW_PU 22 +#define RES4330_MACPHY_CLKAVAIL 23 +#define RES4330_HT_AVAIL 24 +#define RES4330_5gRX_PWRSW_PU 25 +#define RES4330_5gTX_PWRSW_PU 26 +#define RES4330_5g_LOGEN_PWRSW_PU 27 + + +#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) +#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) +#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) +#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) +#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) +#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) +#define CST4330_OTP_PRESENT 0x00000010 +#define CST4330_LPO_AUTODET_EN 0x00000020 +#define CST4330_ARMREMAP_0 0x00000040 +#define CST4330_SPROM_PRESENT 0x00000080 +#define CST4330_ILPDIV_EN 0x00000100 +#define CST4330_LPO_SEL 0x00000200 +#define CST4330_RES_INIT_MODE_SHIFT 10 +#define CST4330_RES_INIT_MODE_MASK 0x00000c00 +#define CST4330_CBUCK_MODE_SHIFT 12 +#define CST4330_CBUCK_MODE_MASK 0x00003000 +#define CST4330_CBUCK_POWER_OK 0x00004000 +#define CST4330_BB_PLL_LOCKED 0x00008000 +#define SOCDEVRAM_4330_BP_ADDR 0x1E000000 +#define SOCDEVRAM_4330_ARM_ADDR 0x00800000 + + +#define PCTL_4330_SERIAL_ENAB (1 << 24) + + +#define CCTRL_4330_GPIO_SEL 0x00000001 +#define CCTRL_4330_ERCX_SEL 0x00000002 +#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 +#define CCTRL_4330_JTAG_DISABLE 0x00000008 + + +#define RES4313_BB_PU_RSRC 0 +#define RES4313_ILP_REQ_RSRC 1 +#define RES4313_XTAL_PU_RSRC 2 +#define RES4313_ALP_AVAIL_RSRC 3 +#define RES4313_RADIO_PU_RSRC 4 +#define RES4313_BG_PU_RSRC 5 +#define RES4313_VREG1P4_PU_RSRC 6 +#define RES4313_AFE_PWRSW_RSRC 7 +#define RES4313_RX_PWRSW_RSRC 8 +#define RES4313_TX_PWRSW_RSRC 9 +#define RES4313_BB_PWRSW_RSRC 10 +#define RES4313_SYNTH_PWRSW_RSRC 11 +#define RES4313_MISC_PWRSW_RSRC 12 +#define RES4313_BB_PLL_PWRSW_RSRC 13 +#define RES4313_HT_AVAIL_RSRC 14 +#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 + + +#define CST4313_SPROM_PRESENT 1 +#define CST4313_OTP_PRESENT 2 +#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 +#define CST4313_SPROM_OTP_SEL_SHIFT 0 + + +#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 + + +#define RES43228_NOT_USED 0 +#define RES43228_ILP_REQUEST 1 +#define RES43228_XTAL_PU 2 +#define RES43228_ALP_AVAIL 3 +#define RES43228_PLL_EN 4 +#define RES43228_HT_PHY_AVAIL 5 + + +#define CST43228_ILP_DIV_EN 0x1 +#define CST43228_OTP_PRESENT 0x2 +#define CST43228_SERDES_REFCLK_PADSEL 0x4 +#define CST43228_SDIO_MODE 0x8 +#define CST43228_SDIO_OTP_PRESENT 0x10 +#define CST43228_SDIO_RESET 0x20 + #define PMU_MAX_TRANSITION_DLY 15000 diff --git a/src/include/sbconfig.h b/src/include/sbconfig.h index 252f4d1..76f05ae 100644 --- a/src/include/sbconfig.h +++ b/src/include/sbconfig.h @@ -1,7 +1,7 @@ /* * Broadcom SiliconBackplane hardware register definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: sbconfig.h,v 13.67.30.1 2008/05/07 20:17:27 Exp $ + * $Id: sbconfig.h,v 13.70 2008-03-28 19:17:04 Exp $ */ diff --git a/src/include/sbhnddma.h b/src/include/sbhnddma.h index 16499ed..05d0587 100644 --- a/src/include/sbhnddma.h +++ b/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-2011, 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: sbhnddma.h,v 13.11.250.5 2008/05/07 20:23:46 Exp $ + * $Id: sbhnddma.h,v 13.20.2.3 2010-10-14 22:21:29 Exp $ */ @@ -61,8 +61,10 @@ typedef volatile struct { } dma32dd_t; -#define D32MAXRINGSZ 4096 -#define D32RINGALIGN 4096 +#define D32RINGALIGN_BITS 12 +#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) +#define D32RINGALIGN (1 << D32RINGALIGN_BITS) + #define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) @@ -73,6 +75,8 @@ typedef volatile struct { #define XC_PD ((uint32)1 << 11) #define XC_AE ((uint32)3 << 16) #define XC_AE_SHIFT 16 +#define XC_BL_MASK 0x001C0000 +#define XC_BL_SHIFT 18 #define XP_LD_MASK 0xfff @@ -106,6 +110,8 @@ typedef volatile struct { #define RC_PD ((uint32)1 << 11) #define RC_AE ((uint32)3 << 16) #define RC_AE_SHIFT 16 +#define RC_BL_MASK 0x001C0000 +#define RC_BL_SHIFT 18 #define RP_LD_MASK 0xfff @@ -144,9 +150,10 @@ typedef volatile struct { #define FA_SEL_RSP 0xf0000 -#define CTRL_BC_MASK 0x1fff +#define CTRL_BC_MASK 0x00001fff #define CTRL_AE ((uint32)3 << 16) #define CTRL_AE_SHIFT 16 +#define CTRL_PARITY ((uint32)3 << 18) #define CTRL_EOT ((uint32)1 << 28) #define CTRL_IOC ((uint32)1 << 29) #define CTRL_EOF ((uint32)1 << 30) @@ -188,11 +195,17 @@ typedef volatile struct { } dma64dd_t; -#define D64MAXRINGSZ 8192 -#define D64RINGALIGN 8192 +#define D64RINGALIGN_BITS 13 +#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) +#define D64RINGALIGN (1 << D64RINGALIGN_BITS) + #define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) +#define D64_DEF_USBBURSTLEN 2 +#define D64_DEF_SDIOBURSTLEN 1 + + #define D64_XC_XE 0x00000001 #define D64_XC_SE 0x00000002 #define D64_XC_LE 0x00000004 @@ -200,6 +213,8 @@ typedef volatile struct { #define D64_XC_PD 0x00000800 #define D64_XC_AE 0x00030000 #define D64_XC_AE_SHIFT 16 +#define D64_XC_BL_MASK 0x001C0000 +#define D64_XC_BL_SHIFT 18 #define D64_XP_LD_MASK 0x00000fff @@ -214,7 +229,7 @@ typedef volatile struct { #define D64_XS0_XS_STOPPED 0x30000000 #define D64_XS0_XS_SUSP 0x40000000 -#define D64_XS1_AD_MASK 0x0001ffff +#define D64_XS1_AD_MASK 0x00001fff #define D64_XS1_XE_MASK 0xf0000000 #define D64_XS1_XE_SHIFT 28 #define D64_XS1_XE_NOERR 0x00000000 @@ -234,6 +249,15 @@ typedef volatile struct { #define D64_RC_PD 0x00000800 #define D64_RC_AE 0x00030000 #define D64_RC_AE_SHIFT 16 +#define D64_RC_BL_MASK 0x001C0000 +#define D64_RC_BL_SHIFT 18 + + +#define DMA_CTRL_PEN (1 << 0) +#define DMA_CTRL_ROC (1 << 1) +#define DMA_CTRL_RXMULTI (1 << 2) +#define DMA_CTRL_UNFRAMED (1 << 3) +#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) #define D64_RP_LD_MASK 0x00000fff @@ -274,6 +298,7 @@ typedef volatile struct { #define D64_FA_SEL_RSP 0xf0000 +#define D64_CTRL_COREFLAGS 0x0ff00000 #define D64_CTRL1_EOT ((uint32)1 << 28) #define D64_CTRL1_IOC ((uint32)1 << 29) #define D64_CTRL1_EOF ((uint32)1 << 30) @@ -288,5 +313,15 @@ typedef volatile struct { #define D64_CTRL_CORE_MASK 0x0ff00000 +#define D64_RX_FRM_STS_LEN 0x0000ffff +#define D64_RX_FRM_STS_OVFL 0x00800000 +#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 +#define D64_RX_FRM_STS_DATATYPE 0xf0000000 + + +typedef volatile struct { + uint16 len; + uint16 flags; +} dma_rxh_t; #endif diff --git a/src/include/sbpcmcia.h b/src/include/sbpcmcia.h index f96a918..aba914b 100644 --- a/src/include/sbpcmcia.h +++ b/src/include/sbpcmcia.h @@ -1,7 +1,7 @@ /* * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: sbpcmcia.h,v 13.31.4.1.2.5.6.3 2009/01/29 01:19:50 Exp $ + * $Id: sbpcmcia.h,v 13.48.12.6 2010-11-04 09:39:42 Exp $ */ diff --git a/src/include/sbsdio.h b/src/include/sbsdio.h index 6ad8926..4280d5b 100644 --- a/src/include/sbsdio.h +++ b/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-2011, 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: sbsdio.h,v 13.29.4.1.4.1 2008/09/04 00:41:38 Exp $ + * $Id: sbsdio.h,v 13.34 2009-03-11 20:27:16 Exp $ */ #ifndef _SBSDIO_H @@ -45,9 +45,9 @@ #define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ /* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ -#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b31-b24) */ -#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23-b16) */ -#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b15) */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ #define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ #define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ #define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ @@ -123,10 +123,10 @@ (alponly ? 1 : SBSDIO_HTAV(regval))) /* SBSDIO_FUNC1_SDIOPULLUP */ -#define SBSDIO_PULLUP_D0 0x01 /* Enable D0 pullup */ -#define SBSDIO_PULLUP_D1 0x02 /* Enable D1 pullup */ +#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ +#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ #define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ -#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD pullup */ +#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ #define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ /* function 1 OCP space */ @@ -136,10 +136,10 @@ /* some duplication with sbsdpcmdev.h here */ /* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ -#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ -#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ -#define SBSDIO_SBADDRHIGH_MASK 0xff /* Valid bits in SBADDRHIGH */ -#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ +#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ +#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ +#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ +#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ /* direct(mapped) cis space */ #define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ diff --git a/src/include/sbsdpcmdev.h b/src/include/sbsdpcmdev.h index 7e0d906..107a8b0 100644 --- a/src/include/sbsdpcmdev.h +++ b/src/include/sbsdpcmdev.h @@ -2,7 +2,7 @@ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific * device core support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: sbsdpcmdev.h,v 13.29.4.1.4.6 2008/07/11 21:26:55 Exp $ + * $Id: sbsdpcmdev.h,v 13.38 2009-09-22 22:56:45 Exp $ */ #ifndef _sbsdpcmdev_h_ @@ -48,12 +48,11 @@ typedef volatile struct { dma64p_t dma64regs[2]; dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ uint32 PAD[92]; - } sdiodma64_t; -/* dma64 sdiod corerev == 0 */ +/* dma32 sdiod corerev == 0 */ typedef volatile struct { - dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ + dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ uint32 PAD[108]; } sdiodma32_t; @@ -88,22 +87,22 @@ typedef volatile struct { uint32 intmask; /* IntSbMask, 0x028, rev8 */ uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ - uint32 PAD[3]; + uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ + uint32 PAD[2]; uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ - /* synchronized access to registers in SDIO clock domain */ uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ uint32 PAD[3]; /* PCMCIA frame control */ - uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ - uint8 PAD[3]; - uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ - uint8 PAD[155]; + uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ + uint8 PAD[3]; + uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ + uint8 PAD[155]; /* interrupt batching control */ uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ @@ -161,10 +160,12 @@ typedef volatile struct { } sdpcmd_regs_t; /* corecontrol */ -#define CC_CISRDY (1 << 0) /* CIS Ready */ -#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ -#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ -#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ +#define CC_CISRDY (1 << 0) /* CIS Ready */ +#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ +#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ +#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ +#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ +#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ /* corestatus */ #define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ @@ -176,7 +177,7 @@ typedef volatile struct { #define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ #define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ -/* intstatus - hw defs */ +/* intstatus */ #define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ #define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ #define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ @@ -199,6 +200,7 @@ typedef volatile struct { #define I_XU (1 << 15) /* Transmit fifo Underflow */ #define I_RI (1 << 16) /* Receive Interrupt */ #define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ +#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ #define I_XI (1 << 24) /* Transmit Interrupt */ #define I_RF_TERM (1 << 25) /* Read Frame Terminate */ #define I_WF_TERM (1 << 26) /* Write Frame Terminate */ @@ -209,9 +211,6 @@ typedef volatile struct { #define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ #define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */ #define I_DMA (I_RI | I_XI | I_ERRORS) -/* ToSbMailbox and ToHostMailbox Ints */ -#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) -#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) /* ToHostMailbox */ /* sbintstatus */ #define I_SB_SERR (1 << 8) /* Backplane SError (write) */ @@ -291,191 +290,4 @@ typedef volatile struct { /* HW frame tag */ #define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ -/* - * ******************************************************************* - * SOFTWARE DEFINITIONS - * ******************************************************************* - */ - -/* intstatus register - sw defs */ -#define I_SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ -#define I_SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ -#define I_SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ -#define I_SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ -#define I_HMB_FC_STATE (1 << 4) /* To Host Mailbox Flow Control State */ -#define I_HMB_FC_CHANGE (1 << 5) /* To Host Mailbox Flow Control State Changed */ -#define I_HMB_FRAME_IND (1 << 6) /* To Host Mailbox Frame Indication */ -#define I_HMB_HOST_INT (1 << 7) /* To Host Mailbox Miscellaneous Interrupt */ - -/* intstatus register masks for sw mailbox interrupts */ -#define SMB_MASK 0x0000000f /* ToSBMailbox Mask */ -#define HMB_MASK 0x000000f0 /* ToHostMailbox Mask */ -#define HMB_SHIFT 4 /* ToHostMailbox Shift */ - -/* tosbmailbox & tohostmailbox - sw defs */ -#define MB_MASK 0x0000000f /* ToSBMailbox & ToHostMailbox Mask */ -#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ -#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ -#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ -#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ -#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State=ON */ -#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ -#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ -#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ - -/* tohostmailboxdata - sw defs */ -#define HMB_DATA_NAKHANDLED 1 /* we're ready to retransmit NAK'd frame to host */ -#define HMB_DATA_DEVREADY 2 /* we're ready to to talk to host after enable */ -#define HMB_DATA_FC 4 /* per prio flowcontrol update flag to host */ -#define HMB_DATA_FWREADY 8 /* firmware is ready for protocol activity */ - -#define HMB_DATA_FCDATA_MASK 0xff /* per prio flowcontrol data */ -#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ - -#define HMB_DATA_VERSION_MASK 0xff /* device protocol version (with devready) */ -#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ - -/* tosbmailboxdata - sw defs */ -#define SMB_DATA_VERSION_MASK 0xff /* host protocol version (with F2 enable) */ -#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (with F2 enable) */ - -/* current protocol version */ -#define SDPCM_PROT_VERSION 4 - -/* SW frame header */ -#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ -#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ - -#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ -#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ -#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ - -#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ -#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ -#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ - -/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ -#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ -#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ -#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ -#define SDPCM_NEXTLEN_OFFSET 2 - -/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ -#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ -#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) -#define SDPCM_DOFFSET_MASK 0xff000000 -#define SDPCM_DOFFSET_SHIFT 24 - -#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ -#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) -#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) -#define SDPCM_VERSION_OFFSET 6 /* Version # */ -#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) -#define SDPCM_UNUSED_OFFSET 7 /* Spare */ -#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) - -#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ - -/* logical channel numbers */ -#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ -#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ -#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ -#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ -#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ -#define SDPCM_MAX_CHANNEL 15 - -#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ - -#define SDPCM_FLAG_RESVD0 0x01 -#define SDPCM_FLAG_RESVD1 0x02 -#define SDPCM_FLAG_GSPI_TXENAB 0x04 -#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ - -/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ -#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) - -#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) - -/* For TEST_CHANNEL packets, define another 4-byte header */ -#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); - * Semantics of Ext byte depend on command. - * Len is current or requested frame length, not - * including test header; sent little-endian. - */ -#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ -#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ -#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ -#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count */ -#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off */ - -/* Handy macro for filling in datagen packets with a pattern */ -#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) - - -/* software copy of hardware counters */ -typedef volatile struct { - uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ - uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ - uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ - uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ - uint32 abort; /* AbortCount, SDIO: aborts */ - uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ - uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ - uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ - uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ - uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ - uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ - uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ - uint32 rxdescuflo; /* receive descriptor underflows */ - uint32 rxfifooflo; /* receive fifo overflows */ - uint32 txfifouflo; /* transmit fifo underflows */ - uint32 runt; /* runt (too short) frames recv'd from bus */ - uint32 badlen; /* frame's rxh len does not match its hw tag len */ - uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ - uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ - uint32 rxfcrc; /* frame rx header indicates crc error */ - uint32 rxfwoos; /* frame rx header indicates write out of sync */ - uint32 rxfwft; /* frame rx header indicates write frame termination */ - uint32 rxfabort; /* frame rx header indicates frame aborted */ - uint32 woosint; /* write out of sync interrupt */ - uint32 roosint; /* read out of sync interrupt */ - uint32 rftermint; /* read frame terminate interrupt */ - uint32 wftermint; /* write frame terminate interrupt */ -} sdpcmd_cnt_t; - -#define SDIODREV_IS(var, val) ((var) == (val)) -#define SDIODREV_GE(var, val) ((var) >= (val)) -#define SDIODREV_GT(var, val) ((var) > (val)) -#define SDIODREV_LT(var, val) ((var) < (val)) -#define SDIODREV_LE(var, val) ((var) <= (val)) - -#define SDIODDMAREG(h, dir, chnl) (SDIODREV_LT(h->corerev, 1) ? \ - ((dir == DMA_TX) ? \ - (void*)(uintptr)&(h->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ - (void*)(uintptr)&(h->regs->dma.sdiod32.dma32regs[chnl].rcv)) : \ - ((dir == DMA_TX) ? \ - (void*)(uintptr)&(h->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ - (void*)(uintptr)&(h->regs->dma.sdiod64.dma64regs[chnl].rcv))) - -#define PCMDDMAREG(h, dir, chnl) \ - ((dir == DMA_TX) ? \ - (void*)(uintptr)&(h->regs->dma.pcm32.dmaregs.xmt) : \ - (void*)(uintptr)&(h->regs->dma.pcm32.dmaregs.rcv)) - -#define SDPCMDMAREG(h, dir, chnl, coreid) ((coreid == SDIOD_CORE_ID) ? \ - (SDIODDMAREG(h, dir, chnl)) : (PCMDDMAREG(h, dir, chnl))) - -#define SDIODFIFOREG(h, corerev) (SDIODREV_LT(corerev, 1) ? \ - ((dma32diag_t *)(uintptr)&(h->regs->dma.sdiod32.dmafifo)) : \ - ((dma32diag_t *)(uintptr)&(h->regs->dma.sdiod64.dmafifo))) - - -#define PCMDFIFOREG(h) \ - ((dma32diag_t*)(uintptr)&(h->regs->dma.pcm32.dmafifo)) - -#define SDPCMFIFOREG(h, coreid, corerev) ((coreid == SDIOD_CORE_ID) ? \ - (SDIODFIFOREG(h, corerev)) : (PCMDFIFOREG(h))) - - #endif /* _sbsdpcmdev_h_ */ diff --git a/src/include/sbsocram.h b/src/include/sbsocram.h index eaa4142..1cba422 100644 --- a/src/include/sbsocram.h +++ b/src/include/sbsocram.h @@ -1,7 +1,7 @@ /* * BCM47XX Sonics SiliconBackplane embedded ram core * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: sbsocram.h,v 13.9 2007/06/30 01:58:35 Exp $ + * $Id: sbsocram.h,v 13.15 2009-10-02 16:55:44 Exp $ */ @@ -41,12 +41,37 @@ typedef volatile struct sbsocramregs { uint32 coreinfo; uint32 bwalloc; - uint32 PAD; + uint32 extracoreinfo; uint32 biststat; uint32 bankidx; uint32 standbyctrl; - uint32 PAD[116]; + + uint32 errlogstatus; + uint32 errlogaddr; + + uint32 cambankidx; + uint32 cambankstandbyctrl; + uint32 cambankpatchctrl; + uint32 cambankpatchtblbaseaddr; + uint32 cambankcmdreg; + uint32 cambankdatareg; + uint32 cambankmaskreg; + uint32 PAD[1]; + uint32 bankinfo; + uint32 PAD[15]; + uint32 extmemconfig; + uint32 extmemparitycsr; + uint32 extmemparityerrdata; + uint32 extmemparityerrcnt; + uint32 extmemwrctrlandsize; + uint32 PAD[84]; + uint32 workaround; uint32 pwrctl; + uint32 PAD[133]; + uint32 sr_control; + uint32 sr_status; + uint32 sr_address; + uint32 sr_data; } sbsocramregs_t; #endif @@ -60,9 +85,16 @@ typedef volatile struct sbsocramregs { #define SR_PWRCTL 0x1e8 -#define SRCI_PT_MASK 0x00030000 +#define SRCI_PT_MASK 0x00070000 #define SRCI_PT_SHIFT 16 +#define SRCI_PT_OCP_OCP 0 +#define SRCI_PT_AXI_OCP 1 +#define SRCI_PT_ARM7AHB_OCP 2 +#define SRCI_PT_CM3AHB_OCP 3 +#define SRCI_PT_AXI_AXI 4 +#define SRCI_PT_AHB_AXI 5 + #define SRCI_LSS_MASK 0x00f00000 #define SRCI_LSS_SHIFT 20 #define SRCI_LRS_MASK 0x0f000000 @@ -100,4 +132,55 @@ typedef volatile struct sbsocramregs { #define SRPC_STBYOVR_MASK 0x00000007 #define SRPC_STBYOVR_SHIFT 0 + +#define SRECC_NUM_BANKS_MASK 0x000000F0 +#define SRECC_NUM_BANKS_SHIFT 4 +#define SRECC_BANKSIZE_MASK 0x0000000F +#define SRECC_BANKSIZE_SHIFT 0 + +#define SRECC_BANKSIZE(value) (1 << (value)) + + +#define SRCBPC_PATCHENABLE 0x80000000 + +#define SRP_ADDRESS 0x0001FFFC +#define SRP_VALID 0x8000 + + +#define SRCMD_WRITE 0x00020000 +#define SRCMD_READ 0x00010000 +#define SRCMD_DONE 0x80000000 + +#define SRCMD_DONE_DLY 1000 + + +#define SOCRAM_BANKINFO_SZMASK 0x3f +#define SOCRAM_BANKIDX_ROM_MASK 0x100 + +#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 + +#define SOCRAM_MEMTYPE_RAM 0 +#define SOCRAM_MEMTYPE_R0M 1 +#define SOCRAM_MEMTYPE_DEVRAM 2 + +#define SOCRAM_BANKINFO_REG 0x40 +#define SOCRAM_BANKIDX_REG 0x10 +#define SOCRAM_BANKINFO_STDBY_MASK 0x400 +#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 + + +#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 +#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 +#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 +#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 + + +#define SOCRAM_DEVRAMBANK_MASK 0xF000 +#define SOCRAM_DEVRAMBANK_SHIFT 12 + + +#define SOCRAM_BANKINFO_SZBASE 8192 +#define SOCRAM_BANKSIZE_SHIFT 13 + + #endif diff --git a/src/include/sdio.h b/src/include/sdio.h index edb7889..7e94e7d 100644 --- a/src/include/sdio.h +++ b/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-2011, 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: sdio.h,v 13.24.4.1.4.1 2008/05/06 22:57:29 Exp $ + * $Id: sdio.h,v 13.27.14.1 2010-09-07 13:37:45 Exp $ */ #ifndef _SDIO_H @@ -79,6 +79,12 @@ typedef volatile struct { #define SDIOD_CCCR_BLKSIZE_1 0x11 #define SDIOD_CCCR_POWER_CONTROL 0x12 #define SDIOD_CCCR_SPEED_CONTROL 0x13 +#define SDIOD_CCCR_UHSI_SUPPORT 0x14 +#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 +#define SDIOD_CCCR_INTR_EXTN 0x16 + +/* Broadcom extensions (corerev >= 1) */ +#define SDIOD_CCCR_BRCM_SEPINT 0xf2 /* cccr_sdio_rev */ #define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ @@ -134,6 +140,35 @@ typedef volatile struct { #define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ #define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ +/* for setting bus speed in card: 0x13h */ +#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSISEL_S 1 + +/* for getting bus speed cap in card: 0x14h */ +#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) +#define SDIO_BUS_SPEED_UHSICAP_S 0 + +/* for getting driver type CAP in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) +#define SDIO_BUS_DRVR_TYPE_CAP_S 0 + +/* for setting driver type selection in card: 0x15h */ +#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) +#define SDIO_BUS_DRVR_TYPE_SEL_S 4 + +/* for getting async int support in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_CAP_S 0 + +/* for setting async int selection in card: 0x16h */ +#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) +#define SDIO_BUS_ASYNCINT_SEL_S 1 + +/* brcm sepint */ +#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ +#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ +#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ + /* FBR structure for function 1-7, FBR addresses and register offsets */ typedef volatile struct { uint8 devctr; /* device interface, CSA control */ @@ -162,7 +197,7 @@ typedef volatile struct { #define SDIOD_FBR_SIZE 0x100 /* Macro to calculate FBR register base */ -#define SDIOD_FBR_BASE(n) (n * 0x100) +#define SDIOD_FBR_BASE(n) ((n) * 0x100) /* Function register offsets */ #define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ @@ -282,13 +317,13 @@ typedef volatile struct { /* build SD_CMD_IO_RW_DIRECT Argument */ #define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ - (((rw & 1) << 31) | ((func & 0x7) << 28) | ((raw & 1) << 27) | \ - ((addr & 0x1FFFF) << 9) | (data & 0xFF)) + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ + (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) /* build SD_CMD_IO_RW_EXTENDED Argument */ #define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ - (((rw & 1) << 31) | ((func & 0x7) << 28) | ((blk & 1) << 27) | \ - ((inc_addr & 1) << 26) | ((addr & 0x1FFFF) << 9) | (count & 0x1FF)) + ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ + (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) /* SDIO response parameters */ #define SD_RSP_NO_NONE 0 @@ -340,7 +375,9 @@ typedef volatile struct { #define SDIOH_CMD_3 3 #define SDIOH_CMD_5 5 #define SDIOH_CMD_7 7 +#define SDIOH_CMD_11 11 #define SDIOH_CMD_15 15 +#define SDIOH_CMD_19 19 #define SDIOH_CMD_52 52 #define SDIOH_CMD_53 53 #define SDIOH_CMD_59 59 @@ -369,6 +406,9 @@ typedef volatile struct { #define CMD5_OCR_M BITFIELD_MASK(24) #define CMD5_OCR_S 0 +#define CMD5_S18R_M BITFIELD_MASK(1) +#define CMD5_S18R_S 24 + #define CMD7_RCA_M BITFIELD_MASK(16) #define CMD7_RCA_S 16 @@ -407,6 +447,10 @@ typedef volatile struct { */ #define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ #define RSP4_IO_OCR_S 0 + +#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ +#define RSP4_S18A_S 24 + #define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ #define RSP4_STUFF_S 24 #define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ @@ -555,4 +599,8 @@ typedef volatile struct { #define SDIOH_XFER_TYPE_READ SD_IO_OP_READ #define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE +/* command issue options */ +#define CMD_OPTION_DEFAULT 0 +#define CMD_OPTION_TUNING 1 + #endif /* _SDIO_H */ diff --git a/src/include/sdioh.h b/src/include/sdioh.h index 4bcdca1..3d37c7a 100644 --- a/src/include/sdioh.h +++ b/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-2011, 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.2 2008/09/30 17:52:35 Exp $ + * $Id: sdioh.h,v 13.17.2.3 2011-01-08 05:28:21 Exp $ */ #ifndef _SDIOH_H @@ -61,26 +61,58 @@ #define SD_ErrorIntrSignalEnable 0x03A #define SD_CMD12ErrorStatus 0x03C #define SD_Capabilities 0x040 -#define SD_Capabilities_Reserved 0x044 +#define SD_Capabilities3 0x044 #define SD_MaxCurCap 0x048 #define SD_MaxCurCap_Reserved 0x04C +#define SD_ADMA_ErrStatus 0x054 +#define SD_ADMA_SysAddr 0x58 #define SD_SlotInterruptStatus 0x0FC #define SD_HostControllerVersion 0x0FE /* SD specific registers in PCI config space */ #define SD_SlotInfo 0x40 +/* HC 3.0 specific registers and offsets */ +#define SD3_HostCntrl2 0x03E +/* preset regsstart and count */ +#define SD3_PresetValStart 0x060 +#define SD3_PresetValCount 8 +/* preset-indiv regs */ +#define SD3_PresetVal_init 0x060 +#define SD3_PresetVal_default 0x062 +#define SD3_PresetVal_HS 0x064 +#define SD3_PresetVal_SDR12 0x066 +#define SD3_PresetVal_SDR25 0x068 +#define SD3_PresetVal_SDR50 0x06a +#define SD3_PresetVal_SDR104 0x06c +#define SD3_PresetVal_DDR50 0x06e + +/* preset value indices */ +#define SD3_PRESETVAL_INITIAL_IX 0 +#define SD3_PRESETVAL_DESPEED_IX 1 +#define SD3_PRESETVAL_HISPEED_IX 2 +#define SD3_PRESETVAL_SDR12_IX 3 +#define SD3_PRESETVAL_SDR25_IX 4 +#define SD3_PRESETVAL_SDR50_IX 5 +#define SD3_PRESETVAL_SDR104_IX 6 +#define SD3_PRESETVAL_DDR50_IX 7 + /* SD_Capabilities reg (0x040) */ #define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) #define CAP_TO_CLKFREQ_S 0 #define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) #define CAP_TO_CLKUNIT_S 7 -#define CAP_BASECLK_M BITFIELD_MASK(6) +/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 + bits are reserved. going ahead with 8 bits, as it is req for 3.0 +*/ +#define CAP_BASECLK_M BITFIELD_MASK(8) #define CAP_BASECLK_S 8 #define CAP_MAXBLOCK_M BITFIELD_MASK(2) #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) @@ -96,6 +128,60 @@ #define CAP_64BIT_HOST_M BITFIELD_MASK(1) #define CAP_64BIT_HOST_S 28 +#define SDIO_OCR_READ_FAIL (2) + + +#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) +#define CAP_ASYNCINT_SUP_S 29 + +#define CAP_SLOTTYPE_M BITFIELD_MASK(2) +#define CAP_SLOTTYPE_S 30 + +#define CAP3_MSBits_OFFSET (32) +/* note: following are caps MSB32 bits. + So the bits start from 0, instead of 32. that is why + CAP3_MSBits_OFFSET is subtracted. +*/ +#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) +#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) + +#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) +#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) + +/* for knowing the clk caps in a single read */ +#define CAP3_30CLKCAP_M BITFIELD_MASK(3) +#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) + +#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) +#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) +#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) + +#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) +#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) + +#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) +#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) + +#define CAP3_CLK_MULT_M BITFIELD_MASK(8) +#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) + +#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) +#define PRESET_DRIVR_SELECT_S 14 + +#define PRESET_CLK_DIV_M BITFIELD_MASK(10) +#define PRESET_CLK_DIV_S 0 + /* SD_MaxCurCap reg (0x048) */ #define CAP_CURR_3_3_M BITFIELD_MASK(8) #define CAP_CURR_3_3_S 0 @@ -191,8 +277,35 @@ #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 +/* Host Control2: */ +#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ + +#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ + +#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ + +#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ + +#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ +#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ + +#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ +#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ + +#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ +#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ + +#define HOST_CONTR_VER_2 (1) +#define HOST_CONTR_VER_3 (2) + /* misc defines */ #define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ #define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ @@ -211,7 +324,7 @@ #define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ #define SW_RESET_DAT_S 2 -/* SD_IntStatus: Offset 0x030, size = 2 bytes */ +/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ /* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ #define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ #define INTSTAT_CMD_COMPLETE_S 0 @@ -231,6 +344,8 @@ #define INTSTAT_CARD_REMOVAL_S 7 #define INTSTAT_CARD_INT_M BITFIELD_MASK(1) #define INTSTAT_CARD_INT_S 8 +#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ +#define INTSTAT_RETUNING_INT_S 12 #define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ #define INTSTAT_ERROR_INT_S 15 @@ -256,6 +371,8 @@ #define ERRINT_AUTO_CMD12_S 8 #define ERRINT_VENDOR_M BITFIELD_MASK(4) #define ERRINT_VENDOR_S 12 +#define ERRINT_ADMA_M BITFIELD_MASK(1) +#define ERRINT_ADMA_S 9 /* Also provide definitions in "normal" form to allow combined masks */ #define ERRINT_CMD_TIMEOUT_BIT 0x0001 @@ -267,17 +384,18 @@ #define ERRINT_DATA_ENDBIT_BIT 0x0040 #define ERRINT_CURRENT_LIMIT_BIT 0x0080 #define ERRINT_AUTO_CMD12_BIT 0x0100 +#define ERRINT_ADMA_BIT 0x0200 /* Masks to select CMD vs. DATA errors */ #define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) #define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ - ERRINT_DATA_ENDBIT_BIT) + ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) #define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) /* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ /* SD_ClockCntrl : Offset 0x02C , size = bytes */ -/* SD_SoftwarewReset_TimeoutCntrl : Offset 0x02E , size = bytes */ +/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ /* SD_IntrStatus : Offset 0x030 , size = bytes */ /* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ /* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ diff --git a/src/include/sdiovar.h b/src/include/sdiovar.h index dfddc3e..2c5bcf9 100644 --- a/src/include/sdiovar.h +++ b/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-2011, 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.30.1 2008/10/25 00:31:57 Exp $ + * $Id: sdiovar.h,v 13.9 2009-12-08 22:30:15 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/src/include/siutils.h b/src/include/siutils.h index 6b20b64..c5a3383 100644 --- a/src/include/siutils.h +++ b/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-2011, 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.4.6.1 2008/12/22 01:19:33 Exp $ + * $Id: siutils.h,v 13.251.2.10 2011-02-04 05:06:32 Exp $ */ @@ -39,11 +39,13 @@ struct si_pub { uint buscoreidx; int ccrev; uint32 cccaps; + uint32 cccaps_ext; int pmurev; uint32 pmucaps; uint boardtype; uint boardvendor; uint boardflags; + uint boardflags2; uint chip; uint chiprev; uint chippkg; @@ -51,17 +53,17 @@ struct si_pub { bool issim; uint socirev; bool pci_pr32414; + }; -#if defined(WLC_HIGH) && !defined(WLC_LOW) -typedef struct si_pub si_t; -#else + typedef const struct si_pub si_t; -#endif #define SI_OSH NULL +#define BADIDX (SI_MAXCORES + 1) + #define XTAL 0x1 #define PLL 0x2 @@ -132,6 +134,7 @@ extern void *si_osh(si_t *sih); extern void si_setosh(si_t *sih, osl_t *osh); extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); extern void *si_coreregs(si_t *sih); +extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); @@ -146,11 +149,10 @@ extern uint32 si_addrspace(si_t *sih, uint asidx); extern uint32 si_addrspacesize(si_t *sih, uint asidx); extern int si_corebist(si_t *sih); extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void si_core_tofixup(si_t *sih); extern void si_core_disable(si_t *sih, uint32 bits); extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); +extern bool si_read_pmu_autopll(si_t *sih); extern uint32 si_clock(si_t *sih); -extern void si_clock_pmu_spuravoid(si_t *sih, bool spuravoid); extern uint32 si_alp_clock(si_t *sih); extern uint32 si_ilp_clock(si_t *sih); extern void si_pci_setup(si_t *sih, uint coremask); @@ -165,10 +167,12 @@ extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); extern bool si_clkctl_cc(si_t *sih, uint mode); extern int si_clkctl_xtal(si_t *sih, uint what, bool on); extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); -extern bool si_backplane64(si_t *sih); extern void si_btcgpiowar(si_t *sih); extern bool si_deviceremoved(si_t *sih); extern uint32 si_socram_size(si_t *sih); +extern uint32 si_socdevram_size(si_t *sih); +extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect); +extern bool si_socdevram_pkg(si_t *sih); extern void si_watchdog(si_t *sih, uint ticks); extern void si_watchdog_ms(si_t *sih, uint32 ms); @@ -195,7 +199,8 @@ extern void si_gpio_handler_process(si_t *sih); extern bool si_pci_pmecap(si_t *sih); struct osl_info; extern bool si_pci_fastpmecap(struct osl_info *osh); -extern bool si_pci_pmeclr(si_t *sih); +extern bool si_pci_pmestat(si_t *sih); +extern void si_pci_pmeclr(si_t *sih); extern void si_pci_pmeen(si_t *sih); extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); @@ -205,8 +210,9 @@ extern uint16 si_d11_devid(si_t *sih); extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); +#define si_eci(sih) 0 #define si_eci_init(sih) (0) -#define si_eci_notify_bt(sih, type, val, interrupt) (0) +#define si_eci_notify_bt(sih, type, val) (0) @@ -217,19 +223,25 @@ extern int si_getdevpathintvar(si_t *sih, const char *name); extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); +extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); extern void si_war42780_clkreq(si_t *sih, bool clkreq); extern void si_pci_sleep(si_t *sih); extern void si_pci_down(si_t *sih); extern void si_pci_up(si_t *sih); -extern void si_pcie_war_ovr_disable(si_t *sih); +extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); extern void si_pcie_extendL1timer(si_t *sih, bool extend); extern int si_pci_fixcfg(si_t *sih); +extern uint si_pll_reset(si_t *sih); +extern bool si_taclear(si_t *sih, bool details); +extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); +extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); +char *si_getnvramflvar(si_t *sih, const char *name); #endif diff --git a/src/include/trxhdr.h b/src/include/trxhdr.h index c7bb3ec..397006a 100644 --- a/src/include/trxhdr.h +++ b/src/include/trxhdr.h @@ -1,7 +1,7 @@ /* * TRX image file header format. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,16 +21,20 @@ * 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: trxhdr.h,v 13.11.310.1 2008/08/17 12:58:58 Exp $ + * $Id: trxhdr.h,v 13.15.108.2 2010-11-15 17:57:30 Exp $ */ +#ifndef _TRX_HDR_H_ +#define _TRX_HDR_H_ + #include <typedefs.h> #define TRX_MAGIC 0x30524448 /* "HDR0" */ #define TRX_VERSION 1 /* Version 1 */ -#define TRX_MAX_LEN 0x3A0000 /* Max length */ +#define TRX_MAX_LEN 0x3B0000 /* Max length */ #define TRX_NO_HEADER 1 /* Do not write TRX header */ #define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ +#define TRX_OVERLAYS 0x4 /* Contains an overlay header after the trx header */ #define TRX_MAX_OFFSET 3 /* Max number of individual files */ #define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ @@ -44,3 +48,5 @@ struct trx_header { /* Compatibility */ typedef struct trx_header TRXHDR, *PTRXHDR; + +#endif /* _TRX_HDR_H_ */ diff --git a/src/include/typedefs.h b/src/include/typedefs.h index 5fb922a..228b5dc 100644 --- a/src/include/typedefs.h +++ b/src/include/typedefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -18,15 +18,13 @@ * 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: typedefs.h,v 1.85.34.1.16.4 2009/09/09 20:58:00 Exp $ + * $Id: typedefs.h,v 1.103.2.1 2010-05-11 18:19:28 Exp $ */ #ifndef _TYPEDEFS_H_ #define _TYPEDEFS_H_ - - #ifdef SITE_TYPEDEFS @@ -37,8 +35,6 @@ - - #ifdef __cplusplus #define TYPEDEF_BOOL @@ -54,7 +50,6 @@ #endif - #if defined(__x86_64__) #define TYPEDEF_UINTPTR typedef unsigned long long int uintptr; @@ -63,26 +58,22 @@ typedef unsigned long long int uintptr; -#if defined(TARGETOS_nucleus) - -#include <stddef.h> - - -#define TYPEDEF_FLOAT_T -#endif #if defined(_NEED_SIZE_T_) typedef long unsigned int size_t; #endif -#ifdef __DJGPP__ -typedef long unsigned int size_t; -#endif +#if defined(__sparc__) +#define TYPEDEF_ULONG +#endif + + +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) #define TYPEDEF_UINT #ifndef TARGETENV_android #define TYPEDEF_USHORT @@ -93,7 +84,15 @@ typedef long unsigned int size_t; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) #define TYPEDEF_BOOL #endif + +#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) +#include <linux/compiler.h> +#ifdef noinline_for_stack +#define TYPEDEF_BOOL +#endif +#endif #endif +#endif @@ -115,12 +114,15 @@ typedef long unsigned int size_t; #endif -#if !defined(__DJGPP__) && !defined(TARGETOS_nucleus) +#if !defined(__DJGPP__) #if defined(__KERNEL__) + +#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) #include <linux/types.h> +#endif #else @@ -204,19 +206,6 @@ typedef signed int int32; typedef signed long long int64; #endif -#ifndef TYPEDEF_CPLXSHORT -typedef struct { - int16 x, y; -} ComplexShort; -#endif - -#ifndef TYPEDEF_CPLXINT -typedef struct { - int32 x, y; -} ComplexInt; -#endif - - #ifndef TYPEDEF_FLOAT32 @@ -273,7 +262,7 @@ typedef float64 float_t; #if defined(__GNUC__) #define BWL_COMPILER_GNU -#elif __CC_ARM +#elif defined(__CC_ARM) && __CC_ARM #define BWL_COMPILER_ARMCC #else #error "Unknown compiler!" @@ -309,9 +298,6 @@ typedef float64 float_t; #undef TYPEDEF_FLOAT32 #undef TYPEDEF_FLOAT64 #undef TYPEDEF_FLOAT_T -#undef TYPEDEF_CPLXSHORT -#undef TYPEDEF_CPLXINT - #endif @@ -320,5 +306,4 @@ typedef float64 float_t; #include <bcmdefs.h> - #endif diff --git a/src/include/wlfc_proto.h b/src/include/wlfc_proto.h new file mode 100644 index 0000000..7230d3b --- /dev/null +++ b/src/include/wlfc_proto.h @@ -0,0 +1,198 @@ +/* +* Copyright (C) 1999-2011, Broadcom Corporation +* +* Unless you and Broadcom execute a separate written software license +* agreement governing use of this software, this software is licensed to you +* under the terms of the GNU General Public License version 2 (the "GPL"), +* available at http://www.broadcom.com/licenses/GPLv2.php, with the +* following added to such license: +* +* As a special exception, the copyright holders of this software give you +* permission to link this software with independent modules, and to copy and +* distribute the resulting executable under terms of your choice, provided that +* you also meet, for each linked independent module, the terms and conditions of +* the license of that module. An independent module is a module which is not +* derived from this software. The special exception does not apply to any +* modifications of the software. +* +* 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: wlfc_proto.h,v 1.1.6.2 2010-05-08 01:30:41 Exp $ +* +*/ +#ifndef __wlfc_proto_definitions_h__ +#define __wlfc_proto_definitions_h__ + + /* Use TLV to convey WLFC information. + --------------------------------------------------------------------------- + | Type | Len | value | Description + --------------------------------------------------------------------------- + | 1 | 1 | (handle) | MAC OPEN + --------------------------------------------------------------------------- + | 2 | 1 | (handle) | MAC CLOSE + --------------------------------------------------------------------------- + | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn + --------------------------------------------------------------------------- + | 4 | 4 | see pkttag comments | TXSTATUS + --------------------------------------------------------------------------- + | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] + --------------------------------------------------------------------------- + | 6 | 8 | (handle, ifid, MAC) | MAC ADD + --------------------------------------------------------------------------- + | 7 | 8 | (handle, ifid, MAC) | MAC DEL + --------------------------------------------------------------------------- + | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. + --------------------------------------------------------------------------- + | 9 | 1 | (interface ID) | Interface OPEN + --------------------------------------------------------------------------- + | 10 | 1 | (interface ID) | Interface CLOSE + --------------------------------------------------------------------------- + | 11 | 8 | fifo credit returns map | FIFO credits back to the host + | | | | + | | | | -------------------------------------- + | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | + | | | | -------------------------------------- + | | | | + --------------------------------------------------------------------------- + | 12 | 2 | MAC handle, | Host provides a bitmap of pending + | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. + | | | | [host->firmware] + --------------------------------------------------------------------------- + | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific + | | | | MAC destination. + --------------------------------------------------------------------------- + | 255 | N/A | N/A | FILLER - This is a special type + | | | | that has no length or value. + | | | | Typically used for padding. + --------------------------------------------------------------------------- + */ + +#define WLFC_CTL_TYPE_MAC_OPEN 1 +#define WLFC_CTL_TYPE_MAC_CLOSE 2 +#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 +#define WLFC_CTL_TYPE_TXSTATUS 4 +#define WLFC_CTL_TYPE_PKTTAG 5 + +#define WLFC_CTL_TYPE_MACDESC_ADD 6 +#define WLFC_CTL_TYPE_MACDESC_DEL 7 +#define WLFC_CTL_TYPE_RSSI 8 + +#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 +#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 + +#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 + +#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 +#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 + +#define WLFC_CTL_TYPE_FILLER 255 + +#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ + +#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ +#define WLFC_CTL_VALUE_LEN_RSSI 1 + +#define WLFC_CTL_VALUE_LEN_INTERFACE 1 +#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 + +#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 +#define WLFC_CTL_VALUE_LEN_PKTTAG 4 + +/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ +#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 + +#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ +#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ + + + +#define WLFC_PKTID_GEN_MASK 0x80000000 +#define WLFC_PKTID_GEN_SHIFT 31 + +#define WLFC_PKTID_GEN(x) (((x) & WLFC_PKTID_GEN_MASK) >> WLFC_PKTID_GEN_SHIFT) +#define WLFC_PKTID_SETGEN(x, gen) (x) = ((x) & ~WLFC_PKTID_GEN_MASK) | \ + (((gen) << WLFC_PKTID_GEN_SHIFT) & WLFC_PKTID_GEN_MASK) + +#define WLFC_PKTFLAG_PKTFROMHOST 0x01 +#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 + +#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ +#define WL_TXSTATUS_FLAGS_SHIFT 27 + +#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) +#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ + WL_TXSTATUS_FLAGS_MASK) + +#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ +#define WL_TXSTATUS_FIFO_SHIFT 24 + +#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ + ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ + (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) +#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) + +#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ +#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ + ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) +#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) + +/* 32 STA should be enough??, 6 bits; Must be power of 2 */ +#define WLFC_MAC_DESC_TABLE_SIZE 32 +#define WLFC_MAX_IFNUM 16 +#define WLFC_MAC_DESC_ID_INVALID 0xff + +/* b[7:5] -reuse guard, b[4:0] -value */ +#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) + +#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ + (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) + +#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ + ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) + +#define WL_TXSTATUS_GENERATION_MASK 1 +#define WL_TXSTATUS_GENERATION_SHIFT 31 + +#define WLFC_PKTFLAG_SET_GENERATION(x, gen) ((x) = \ + ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ + (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) + +#define WLFC_PKTFLAG_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ + WL_TXSTATUS_GENERATION_MASK) + +#define WLFC_MAX_PENDING_DATALEN 120 + +/* host is free to discard the packet */ +#define WLFC_CTL_PKTFLAG_DISCARD 0 +/* D11 suppressed a packet */ +#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 +/* WL firmware suppressed a packet because MAC is + already in PSMode (short time window) +*/ +#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 +/* Firmware tossed this packet */ +#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 + +#define WLFC_D11_STATUS_INTERPRET(txs) ((((txs)->status & TX_STATUS_SUPR_MASK) >> \ + TX_STATUS_SUPR_SHIFT)) ? WLFC_CTL_PKTFLAG_D11SUPPRESS : WLFC_CTL_PKTFLAG_DISCARD + +#ifdef PROP_TXSTATUS_DEBUG +#define WLFC_DBGMESG(x) printf x +/* wlfc-breadcrumb */ +#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ + {printf("WLFC: %s():%d:caller:%p\n", \ + __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) +#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ + banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) +#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) +#else +#define WLFC_DBGMESG(x) +#define WLFC_BREADCRUMB(x) +#define WLFC_PRINTMAC(banner, ea) +#define WLFC_WHEREIS(s) +#endif + +#endif /* __wlfc_proto_definitions_h__ */ diff --git a/src/include/wlioctl.h b/src/include/wlioctl.h index f23fbb4..c824692 100644 --- a/src/include/wlioctl.h +++ b/src/include/wlioctl.h @@ -4,7 +4,7 @@ * * Definitions subject to change without notice. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,12 +24,12 @@ * 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.15.2.20 2009/09/29 16:26:39 Exp $ + * $Id: wlioctl.h,v 1.767.2.38 2011-02-01 23:04:28 Exp $ */ #ifndef _wlioctl_h_ -#define _wlioctl_h_ +#define _wlioctl_h_ #include <typedefs.h> #include <proto/ethernet.h> @@ -38,82 +38,140 @@ #include <proto/802.11.h> #include <bcmwifi.h> +#include <bcmcdc.h> +#ifndef INTF_NAME_SIZ +#define INTF_NAME_SIZ 16 +#endif + + +typedef struct remote_ioctl { + cdc_ioctl_t msg; + uint data_len; + char intf_name[INTF_NAME_SIZ]; +} rem_ioctl_t; +#define REMOTE_SIZE sizeof(rem_ioctl_t) #define ACTION_FRAME_SIZE 1040 typedef struct wl_action_frame { - struct ether_addr da; - uint16 len; - uint32 packetId; - uint8 data[ACTION_FRAME_SIZE]; + struct ether_addr da; + uint16 len; + uint32 packetId; + uint8 data[ACTION_FRAME_SIZE]; } wl_action_frame_t; #define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) +typedef struct wl_af_params { + uint32 channel; + int32 dwell_time; + struct ether_addr BSSID; + wl_action_frame_t action_frame; +} wl_af_params_t; + +#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) + #define BWL_DEFAULT_PACKING #include <packed_section_start.h> -#define RWL_ACTION_WIFI_CATEGORY 127 -#define RWL_WIFI_OUI_BYTE1 0x90 -#define RWL_WIFI_OUI_BYTE2 0x4C -#define RWL_WIFI_OUI_BYTE3 0x0F -#define RWL_WIFI_ACTION_FRAME_SIZE sizeof(struct dot11_action_wifi_vendor_specific) -#define RWL_WIFI_DEFAULT 0x00 -#define RWL_WIFI_FIND_MY_PEER 0x09 -#define RWL_WIFI_FOUND_PEER 0x0A -#define RWL_ACTION_WIFI_FRAG_TYPE 0x55 - -#define RWL_REF_MAC_ADDRESS_OFFSET 17 -#define RWL_DUT_MAC_ADDRESS_OFFSET 23 -#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50 -#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51 +#define LEGACY2_WL_BSS_INFO_VERSION 108 +typedef struct wl_bss_info_108 { + uint32 version; + uint32 length; + struct ether_addr BSSID; + uint16 beacon_period; + uint16 capability; + uint8 SSID_len; + uint8 SSID[32]; + struct { + uint count; + uint8 rates[16]; + } rateset; + chanspec_t chanspec; + uint16 atim_window; + uint8 dtim_period; + int16 RSSI; + int8 phy_noise; + + uint8 n_cap; + uint32 nbss_cap; + uint8 ctl_ch; + uint32 reserved32[1]; + uint8 flags; + uint8 reserved[3]; + uint8 basic_mcs[MCSSET_LEN]; + + uint16 ie_offset; + uint32 ie_length; + + +} wl_bss_info_108_t; -#define WL_BSS_INFO_VERSION 108 +#define WL_BSS_INFO_VERSION 109 typedef struct wl_bss_info { - uint32 version; - uint32 length; + uint32 version; + uint32 length; struct ether_addr BSSID; - uint16 beacon_period; - uint16 capability; - uint8 SSID_len; - uint8 SSID[32]; + uint16 beacon_period; + uint16 capability; + uint8 SSID_len; + uint8 SSID[32]; struct { - uint count; - uint8 rates[16]; - } rateset; - chanspec_t chanspec; - uint16 atim_window; - uint8 dtim_period; - int16 RSSI; - int8 phy_noise; - - uint8 n_cap; - uint32 nbss_cap; - uint8 ctl_ch; - uint32 reserved32[1]; - uint8 flags; - uint8 reserved[3]; - uint8 basic_mcs[MCSSET_LEN]; - - uint16 ie_offset; - uint32 ie_length; + uint count; + uint8 rates[16]; + } rateset; + chanspec_t chanspec; + uint16 atim_window; + uint8 dtim_period; + int16 RSSI; + int8 phy_noise; + + uint8 n_cap; + uint32 nbss_cap; + uint8 ctl_ch; + uint32 reserved32[1]; + uint8 flags; + uint8 reserved[3]; + uint8 basic_mcs[MCSSET_LEN]; + + uint16 ie_offset; + uint32 ie_length; + int16 SNR; } wl_bss_info_t; +typedef struct wl_bsscfg { + uint32 wsec; + uint32 WPA_auth; + uint32 wsec_index; + uint32 associated; + uint32 BSS; + uint32 phytest_on; + struct ether_addr prev_BSSID; + struct ether_addr BSSID; +} wl_bsscfg_t; + +typedef struct wl_bss_config { + uint32 atim_window; + uint32 beacon_period; + uint32 chanspec; +} wl_bss_config_t; + + typedef struct wlc_ssid { - uint32 SSID_len; - uchar SSID[32]; + uint32 SSID_len; + uchar SSID[32]; } wlc_ssid_t; @@ -121,19 +179,25 @@ typedef struct wlc_ssid { #define WL_BSSTYPE_INDEP 0 #define WL_BSSTYPE_ANY 2 + +#define WL_SCANFLAGS_PASSIVE 0x01 +#define WL_SCANFLAGS_RESERVED 0x02 +#define WL_SCANFLAGS_PROHIBITED 0x04 + typedef struct wl_scan_params { - wlc_ssid_t ssid; - struct ether_addr bssid; - int8 bss_type; - int8 scan_type; - int32 nprobes; - int32 active_time; - int32 passive_time; - int32 home_time; - int32 channel_num; - uint16 channel_list[1]; + wlc_ssid_t ssid; + struct ether_addr bssid; + int8 bss_type; + uint8 scan_type; + int32 nprobes; + int32 active_time; + int32 passive_time; + int32 home_time; + int32 channel_num; + uint16 channel_list[1]; } wl_scan_params_t; + #define WL_SCAN_PARAMS_FIXED_SIZE 64 @@ -154,6 +218,7 @@ typedef struct wl_iscan_params { wl_scan_params_t params; } wl_iscan_params_t; + #define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) typedef struct wl_scan_results { @@ -163,13 +228,32 @@ typedef struct wl_scan_results { wl_bss_info_t bss_info[1]; } wl_scan_results_t; -#define WL_SCAN_RESULTS_FIXED_SIZE 12 +#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) + + +#define WL_SCAN_RESULTS_SUCCESS 0 +#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 DNGL_RXCTXT_SIZE 45 + +#if defined(SIMPLE_ISCAN) +#define ISCAN_RETRY_CNT 5 +#define ISCAN_STATE_IDLE 0 +#define ISCAN_STATE_SCANING 1 +#define ISCAN_STATE_PENDING 2 -#define WL_SCAN_RESULTS_SUCCESS 0 -#define WL_SCAN_RESULTS_PARTIAL 1 -#define WL_SCAN_RESULTS_PENDING 2 -#define WL_SCAN_RESULTS_ABORTED 3 + +#define WLC_IW_ISCAN_MAXLEN 2048 +typedef struct iscan_buf { + struct iscan_buf * next; + char iscan_buf[WLC_IW_ISCAN_MAXLEN]; +} iscan_buf_t; +#endif #define ESCAN_REQ_VERSION 1 @@ -198,15 +282,28 @@ typedef struct wl_iscan_results { wl_scan_results_t results; } wl_iscan_results_t; + #define WL_ISCAN_RESULTS_FIXED_SIZE \ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) -#define WL_NUMRATES 255 +typedef struct wl_probe_params { + wlc_ssid_t ssid; + struct ether_addr bssid; + struct ether_addr mac; +} wl_probe_params_t; + +#define WL_NUMRATES 16 typedef struct wl_rateset { - uint32 count; - uint8 rates[WL_NUMRATES]; + uint32 count; + uint8 rates[WL_NUMRATES]; } wl_rateset_t; +typedef struct wl_rateset_args { + uint32 count; + uint8 rates[WL_NUMRATES]; + uint8 mcs[MCSSET_LEN]; +} wl_rateset_args_t; + typedef struct wl_uint32_list { @@ -217,25 +314,205 @@ typedef struct wl_uint32_list { typedef struct wl_assoc_params { - struct ether_addr bssid; - int32 chanspec_num; - chanspec_t chanspec_list[1]; + struct ether_addr bssid; + uint16 bssid_cnt; + int32 chanspec_num; + chanspec_t chanspec_list[1]; } wl_assoc_params_t; -#define WL_ASSOC_PARAMS_FIXED_SIZE (sizeof(wl_assoc_params_t) - sizeof(chanspec_t)) +#define WL_ASSOC_PARAMS_FIXED_SIZE (sizeof(wl_assoc_params_t) - sizeof(chanspec_t)) typedef wl_assoc_params_t wl_reassoc_params_t; -#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE +#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE + + +typedef wl_assoc_params_t wl_join_assoc_params_t; +#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE typedef struct wl_join_params { wlc_ssid_t ssid; - wl_assoc_params_t params; + wl_assoc_params_t params; } wl_join_params_t; +#define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t)) + + +typedef struct wl_join_scan_params { + uint8 scan_type; + int32 nprobes; + int32 active_time; + int32 passive_time; + int32 home_time; +} wl_join_scan_params_t; + + +typedef struct wl_extjoin_params { + wlc_ssid_t ssid; + wl_join_scan_params_t scan; + wl_join_assoc_params_t assoc; +} wl_extjoin_params_t; +#define WL_EXTJOIN_PARAMS_FIXED_SIZE (sizeof(wl_extjoin_params_t) - sizeof(chanspec_t)) + +typedef struct { + uint32 num; + chanspec_t list[1]; +} chanspec_list_t; + + +#define NRATE_MCS_INUSE 0x00000080 +#define NRATE_RATE_MASK 0x0000007f +#define NRATE_STF_MASK 0x0000ff00 +#define NRATE_STF_SHIFT 8 +#define NRATE_OVERRIDE 0x80000000 +#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 +#define NRATE_SGI_MASK 0x00800000 +#define NRATE_SGI_SHIFT 23 +#define NRATE_LDPC_CODING 0x00400000 +#define NRATE_LDPC_SHIFT 22 + +#define NRATE_STF_SISO 0 +#define NRATE_STF_CDD 1 +#define NRATE_STF_STBC 2 +#define NRATE_STF_SDM 3 + +#define ANTENNA_NUM_1 1 +#define ANTENNA_NUM_2 2 +#define ANTENNA_NUM_3 3 +#define ANTENNA_NUM_4 4 + +#define ANT_SELCFG_AUTO 0x80 +#define ANT_SELCFG_MASK 0x33 +#define ANT_SELCFG_MAX 4 +#define ANT_SELCFG_TX_UNICAST 0 +#define ANT_SELCFG_RX_UNICAST 1 +#define ANT_SELCFG_TX_DEF 2 +#define ANT_SELCFG_RX_DEF 3 + +#define MAX_STREAMS_SUPPORTED 4 + +typedef struct { + uint8 ant_config[ANT_SELCFG_MAX]; + uint8 num_antcfg; +} wlc_antselcfg_t; + +#define HIGHEST_SINGLE_STREAM_MCS 7 + +#define MAX_CCA_CHANNELS 38 +#define MAX_CCA_SECS 60 + +#define IBSS_MED 15 +#define IBSS_HI 25 +#define OBSS_MED 12 +#define OBSS_HI 25 +#define INTERFER_MED 5 +#define INTERFER_HI 10 + +#define CCA_FLAG_2G_ONLY 0x01 +#define CCA_FLAG_5G_ONLY 0x02 +#define CCA_FLAG_IGNORE_DURATION 0x04 +#define CCA_FLAGS_PREFER_1_6_11 0x10 +#define CCA_FLAG_IGNORE_INTERFER 0x20 + +#define CCA_ERRNO_BAND 1 +#define CCA_ERRNO_DURATION 2 +#define CCA_ERRNO_PREF_CHAN 3 +#define CCA_ERRNO_INTERFER 4 +#define CCA_ERRNO_TOO_FEW 5 + +typedef struct { + uint32 duration; + uint32 congest_ibss; + + uint32 congest_obss; + uint32 interference; + uint32 timestamp; +} cca_congest_t; + +typedef struct { + chanspec_t chanspec; + uint8 num_secs; + cca_congest_t secs[1]; +} cca_congest_channel_req_t; -#define WLC_CNTRY_BUF_SZ 4 +#define WLC_CNTRY_BUF_SZ 4 -#define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t)) +typedef struct wl_country { + char country_abbrev[WLC_CNTRY_BUF_SZ]; + int32 rev; + char ccode[WLC_CNTRY_BUF_SZ]; +} wl_country_t; + +typedef struct wl_channels_in_country { + uint32 buflen; + uint32 band; + char country_abbrev[WLC_CNTRY_BUF_SZ]; + uint32 count; + uint32 channel[1]; +} wl_channels_in_country_t; + +typedef struct wl_country_list { + uint32 buflen; + uint32 band_set; + uint32 band; + uint32 count; + char country_abbrev[1]; +} wl_country_list_t; + +#define WL_NUM_RPI_BINS 8 +#define WL_RM_TYPE_BASIC 1 +#define WL_RM_TYPE_CCA 2 +#define WL_RM_TYPE_RPI 3 + +#define WL_RM_FLAG_PARALLEL (1<<0) + +#define WL_RM_FLAG_LATE (1<<1) +#define WL_RM_FLAG_INCAPABLE (1<<2) +#define WL_RM_FLAG_REFUSED (1<<3) + +typedef struct wl_rm_req_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; + uint32 tsf_h; + uint32 tsf_l; + uint32 dur; +} wl_rm_req_elt_t; + +typedef struct wl_rm_req { + uint32 token; + uint32 count; + void *cb; + void *cb_arg; + wl_rm_req_elt_t req[1]; +} wl_rm_req_t; +#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) + +typedef struct wl_rm_rep_elt { + int8 type; + int8 flags; + chanspec_t chanspec; + uint32 token; + uint32 tsf_h; + uint32 tsf_l; + uint32 dur; + uint32 len; + uint8 data[1]; +} wl_rm_rep_elt_t; +#define WL_RM_REP_ELT_FIXED_LEN 24 + +#define WL_RPI_REP_BIN_NUM 8 +typedef struct wl_rm_rpi_rep { + uint8 rpi[WL_RPI_REP_BIN_NUM]; + int8 rpi_max[WL_RPI_REP_BIN_NUM]; +} wl_rm_rpi_rep_t; + +typedef struct wl_rm_rep { + uint32 token; + uint32 len; + wl_rm_rep_elt_t rep[1]; +} wl_rm_rep_t; +#define WL_RM_REP_FIXED_LEN 8 typedef enum sup_auth_status { @@ -251,131 +528,129 @@ typedef enum sup_auth_status { WLC_SUP_LAST_BASIC_STATE, + WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, - + WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, - + WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, - - WLC_SUP_KEYXCHANGE_PREP_M4, - WLC_SUP_KEYXCHANGE_WAIT_G1, - WLC_SUP_KEYXCHANGE_PREP_G2, + WLC_SUP_KEYXCHANGE_PREP_M4, + WLC_SUP_KEYXCHANGE_WAIT_G1, + WLC_SUP_KEYXCHANGE_PREP_G2 } sup_auth_status_t; -#define CRYPTO_ALGO_OFF 0 -#define CRYPTO_ALGO_WEP1 1 -#define CRYPTO_ALGO_TKIP 2 -#define CRYPTO_ALGO_WEP128 3 -#define CRYPTO_ALGO_AES_CCM 4 -#define CRYPTO_ALGO_AES_OCB_MSDU 5 -#define CRYPTO_ALGO_AES_OCB_MPDU 6 -#define CRYPTO_ALGO_NALG 7 -#ifdef BCMWAPI_WPI -#define CRYPTO_ALGO_SMS4 11 -#endif +#define CRYPTO_ALGO_OFF 0 +#define CRYPTO_ALGO_WEP1 1 +#define CRYPTO_ALGO_TKIP 2 +#define CRYPTO_ALGO_WEP128 3 +#define CRYPTO_ALGO_AES_CCM 4 +#define CRYPTO_ALGO_AES_OCB_MSDU 5 +#define CRYPTO_ALGO_AES_OCB_MPDU 6 +#define CRYPTO_ALGO_NALG 7 -#define WSEC_GEN_MIC_ERROR 0x0001 -#define WSEC_GEN_REPLAY 0x0002 -#define WSEC_GEN_ICV_ERROR 0x0004 +#define WSEC_GEN_MIC_ERROR 0x0001 +#define WSEC_GEN_REPLAY 0x0002 +#define WSEC_GEN_ICV_ERROR 0x0004 -#define WL_SOFT_KEY (1 << 0) -#define WL_PRIMARY_KEY (1 << 1) -#define WL_KF_RES_4 (1 << 4) -#define WL_KF_RES_5 (1 << 5) -#define WL_IBSS_PEER_GROUP_KEY (1 << 6) +#define WL_SOFT_KEY (1 << 0) +#define WL_PRIMARY_KEY (1 << 1) +#define WL_KF_RES_4 (1 << 4) +#define WL_KF_RES_5 (1 << 5) +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) typedef struct wl_wsec_key { - uint32 index; - uint32 len; - uint8 data[DOT11_MAX_KEY_SIZE]; - uint32 pad_1[18]; - uint32 algo; - uint32 flags; - uint32 pad_2[2]; - int pad_3; - int iv_initialized; - int pad_4; + uint32 index; + uint32 len; + uint8 data[DOT11_MAX_KEY_SIZE]; + uint32 pad_1[18]; + uint32 algo; + uint32 flags; + uint32 pad_2[2]; + int pad_3; + int iv_initialized; + int pad_4; struct { - uint32 hi; - uint16 lo; + uint32 hi; + uint16 lo; } rxiv; - uint32 pad_5[2]; - struct ether_addr ea; + uint32 pad_5[2]; + struct ether_addr ea; } wl_wsec_key_t; -#define WSEC_MIN_PSK_LEN 8 -#define WSEC_MAX_PSK_LEN 64 +#define WSEC_MIN_PSK_LEN 8 +#define WSEC_MAX_PSK_LEN 64 -#define WSEC_PASSPHRASE (1<<0) +#define WSEC_PASSPHRASE (1<<0) typedef struct { - ushort key_len; - ushort flags; - uint8 key[WSEC_MAX_PSK_LEN]; + ushort key_len; + ushort flags; + uint8 key[WSEC_MAX_PSK_LEN]; } wsec_pmk_t; -#define WEP_ENABLED 0x0001 -#define TKIP_ENABLED 0x0002 -#define AES_ENABLED 0x0004 -#define WSEC_SWFLAG 0x0008 -#define SES_OW_ENABLED 0x0040 -#ifdef BCMWAPI_WPI -#define SMS4_ENABLED 0x0100 -#endif +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +#define SES_OW_ENABLED 0x0040 -#define WPA_AUTH_DISABLED 0x0000 -#define WPA_AUTH_NONE 0x0001 -#define WPA_AUTH_UNSPECIFIED 0x0002 -#define WPA_AUTH_PSK 0x0004 - -#define WPA2_AUTH_UNSPECIFIED 0x0040 -#define WPA2_AUTH_PSK 0x0080 +#define WPA_AUTH_DISABLED 0x0000 +#define WPA_AUTH_NONE 0x0001 +#define WPA_AUTH_UNSPECIFIED 0x0002 +#define WPA_AUTH_PSK 0x0004 + +#define WPA2_AUTH_UNSPECIFIED 0x0040 +#define WPA2_AUTH_PSK 0x0080 #define BRCM_AUTH_PSK 0x0100 -#define BRCM_AUTH_DPT 0x0200 -#ifdef BCMWAPI_WPI -#define WPA_AUTH_WAPI 0x0400 -#endif +#define BRCM_AUTH_DPT 0x0200 -#define MAXPMKID 16 +#define MAXPMKID 16 -typedef struct _pmkid -{ - struct ether_addr BSSID; - uint8 PMKID[WPA2_PMKID_LEN]; +typedef struct _pmkid { + struct ether_addr BSSID; + uint8 PMKID[WPA2_PMKID_LEN]; } pmkid_t; -typedef struct _pmkid_list -{ - uint32 npmkid; - pmkid_t pmkid[1]; +typedef struct _pmkid_list { + uint32 npmkid; + pmkid_t pmkid[1]; } pmkid_list_t; typedef struct _pmkid_cand { - struct ether_addr BSSID; - uint8 preauth; + struct ether_addr BSSID; + uint8 preauth; } pmkid_cand_t; typedef struct _pmkid_cand_list { - uint32 npmkid_cand; - pmkid_cand_t pmkid_cand[1]; + uint32 npmkid_cand; + pmkid_cand_t pmkid_cand[1]; } pmkid_cand_list_t; +#define WLC_TXFILTER_OVERRIDE_DISABLED 0 +#define WLC_TXFILTER_OVERRIDE_ENABLED 1 + + typedef struct { - uint32 val; + uint32 val; struct ether_addr ea; } scb_val_t; +typedef struct { + uint32 code; + scb_val_t ioctl_args; +} authops_t; + typedef struct channel_info { int hw_channel; @@ -385,8 +660,8 @@ typedef struct channel_info { struct maclist { - uint count; - struct ether_addr ea[1]; + uint count; + struct ether_addr ea[1]; }; @@ -398,836 +673,1031 @@ typedef struct get_pktcnt { uint rx_ocast_good_pkt; } get_pktcnt_t; +#define WL_IOCTL_ACTION_GET 0x0 +#define WL_IOCTL_ACTION_SET 0x1 +#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e +#define WL_IOCTL_ACTION_OVL_RSV 0x20 +#define WL_IOCTL_ACTION_OVL 0x40 +#define WL_IOCTL_ACTION_MASK 0x7e +#define WL_IOCTL_ACTION_OVL_SHIFT 1 + typedef struct wl_ioctl { - uint cmd; - void *buf; - uint len; - uint8 set; - uint used; - uint needed; + uint cmd; + void *buf; + uint len; + uint8 set; + uint used; + uint needed; } wl_ioctl_t; +#define ioctl_subtype set +#define ioctl_pid used +#define ioctl_status needed -#define WLC_IOCTL_MAGIC 0x14e46c77 +typedef struct wlc_rev_info { + uint vendorid; + uint deviceid; + uint radiorev; + uint chiprev; + uint corerev; + uint boardid; + uint boardvendor; + uint boardrev; + uint driverrev; + uint ucoderev; + uint bus; + uint chipnum; + uint phytype; + uint phyrev; + uint anarev; + uint chippkg; +} wlc_rev_info_t; -#define WLC_IOCTL_VERSION 1 +#define WL_REV_INFO_LEGACY_LENGTH 48 -#define WLC_IOCTL_MAXLEN 8192 -#define WLC_IOCTL_SMLEN 256 -#define WLC_IOCTL_MEDLEN 1536 +#define WL_BRAND_MAX 10 +typedef struct wl_instance_info { + uint instance; + char brand[WL_BRAND_MAX]; +} wl_instance_info_t; -#define WLC_GET_MAGIC 0 -#define WLC_GET_VERSION 1 -#define WLC_UP 2 -#define WLC_DOWN 3 -#define WLC_GET_LOOP 4 -#define WLC_SET_LOOP 5 -#define WLC_DUMP 6 -#define WLC_GET_MSGLEVEL 7 -#define WLC_SET_MSGLEVEL 8 -#define WLC_GET_PROMISC 9 -#define WLC_SET_PROMISC 10 - -#define WLC_GET_RATE 12 +typedef struct wl_txfifo_sz { + uint16 magic; + uint16 fifo; + uint16 size; +} wl_txfifo_sz_t; + +#define WL_TXFIFO_SZ_MAGIC 0xa5a5 + + + +#define WLC_IOV_NAME_LEN 30 +typedef struct wlc_iov_trx_s { + uint8 module; + uint8 type; + char name[WLC_IOV_NAME_LEN]; +} wlc_iov_trx_t; + + +#define WLC_IOCTL_MAGIC 0x14e46c77 + + +#define WLC_IOCTL_VERSION 1 + +#define WLC_IOCTL_MAXLEN 8192 +#define WLC_IOCTL_SMLEN 256 +#define WLC_IOCTL_MEDLEN 1536 +#ifdef WLC_HIGH_ONLY +#define WLC_SAMPLECOLLECT_MAXLEN 1024 +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 +#endif + + +#define WLC_GET_MAGIC 0 +#define WLC_GET_VERSION 1 +#define WLC_UP 2 +#define WLC_DOWN 3 +#define WLC_GET_LOOP 4 +#define WLC_SET_LOOP 5 +#define WLC_DUMP 6 +#define WLC_GET_MSGLEVEL 7 +#define WLC_SET_MSGLEVEL 8 +#define WLC_GET_PROMISC 9 +#define WLC_SET_PROMISC 10 +#define WLC_OVERLAY_IOCTL 11 +#define WLC_GET_RATE 12 -#define WLC_GET_INSTANCE 14 +#define WLC_GET_INSTANCE 14 -#define WLC_GET_INFRA 19 -#define WLC_SET_INFRA 20 -#define WLC_GET_AUTH 21 -#define WLC_SET_AUTH 22 -#define WLC_GET_BSSID 23 -#define WLC_SET_BSSID 24 -#define WLC_GET_SSID 25 -#define WLC_SET_SSID 26 -#define WLC_RESTART 27 +#define WLC_GET_INFRA 19 +#define WLC_SET_INFRA 20 +#define WLC_GET_AUTH 21 +#define WLC_SET_AUTH 22 +#define WLC_GET_BSSID 23 +#define WLC_SET_BSSID 24 +#define WLC_GET_SSID 25 +#define WLC_SET_SSID 26 +#define WLC_RESTART 27 -#define WLC_GET_CHANNEL 29 -#define WLC_SET_CHANNEL 30 -#define WLC_GET_SRL 31 -#define WLC_SET_SRL 32 -#define WLC_GET_LRL 33 -#define WLC_SET_LRL 34 -#define WLC_GET_PLCPHDR 35 -#define WLC_SET_PLCPHDR 36 -#define WLC_GET_RADIO 37 -#define WLC_SET_RADIO 38 -#define WLC_GET_PHYTYPE 39 -#define WLC_DUMP_RATE 40 -#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_CHANNEL 29 +#define WLC_SET_CHANNEL 30 +#define WLC_GET_SRL 31 +#define WLC_SET_SRL 32 +#define WLC_GET_LRL 33 +#define WLC_SET_LRL 34 +#define WLC_GET_PLCPHDR 35 +#define WLC_SET_PLCPHDR 36 +#define WLC_GET_RADIO 37 +#define WLC_SET_RADIO 38 +#define WLC_GET_PHYTYPE 39 +#define WLC_DUMP_RATE 40 +#define WLC_SET_RATE_PARAMS 41 +#define WLC_GET_FIXRATE 42 +#define WLC_SET_FIXRATE 43 -#define WLC_GET_KEY 44 -#define WLC_SET_KEY 45 -#define WLC_GET_REGULATORY 46 -#define WLC_SET_REGULATORY 47 -#define WLC_GET_PASSIVE_SCAN 48 -#define WLC_SET_PASSIVE_SCAN 49 -#define WLC_SCAN 50 -#define WLC_SCAN_RESULTS 51 -#define WLC_DISASSOC 52 -#define WLC_REASSOC 53 -#define WLC_GET_ROAM_TRIGGER 54 -#define WLC_SET_ROAM_TRIGGER 55 -#define WLC_GET_ROAM_DELTA 56 -#define WLC_SET_ROAM_DELTA 57 -#define WLC_GET_ROAM_SCAN_PERIOD 58 -#define WLC_SET_ROAM_SCAN_PERIOD 59 -#define WLC_EVM 60 -#define WLC_GET_TXANT 61 -#define WLC_SET_TXANT 62 -#define WLC_GET_ANTDIV 63 -#define WLC_SET_ANTDIV 64 +#define WLC_GET_KEY 44 +#define WLC_SET_KEY 45 +#define WLC_GET_REGULATORY 46 +#define WLC_SET_REGULATORY 47 +#define WLC_GET_PASSIVE_SCAN 48 +#define WLC_SET_PASSIVE_SCAN 49 +#define WLC_SCAN 50 +#define WLC_SCAN_RESULTS 51 +#define WLC_DISASSOC 52 +#define WLC_REASSOC 53 +#define WLC_GET_ROAM_TRIGGER 54 +#define WLC_SET_ROAM_TRIGGER 55 +#define WLC_GET_ROAM_DELTA 56 +#define WLC_SET_ROAM_DELTA 57 +#define WLC_GET_ROAM_SCAN_PERIOD 58 +#define WLC_SET_ROAM_SCAN_PERIOD 59 +#define WLC_EVM 60 +#define WLC_GET_TXANT 61 +#define WLC_SET_TXANT 62 +#define WLC_GET_ANTDIV 63 +#define WLC_SET_ANTDIV 64 -#define WLC_GET_CLOSED 67 -#define WLC_SET_CLOSED 68 -#define WLC_GET_MACLIST 69 -#define WLC_SET_MACLIST 70 -#define WLC_GET_RATESET 71 -#define WLC_SET_RATESET 72 +#define WLC_GET_CLOSED 67 +#define WLC_SET_CLOSED 68 +#define WLC_GET_MACLIST 69 +#define WLC_SET_MACLIST 70 +#define WLC_GET_RATESET 71 +#define WLC_SET_RATESET 72 -#define WLC_LONGTRAIN 74 -#define WLC_GET_BCNPRD 75 -#define WLC_SET_BCNPRD 76 -#define WLC_GET_DTIMPRD 77 -#define WLC_SET_DTIMPRD 78 -#define WLC_GET_SROM 79 -#define WLC_SET_SROM 80 -#define WLC_GET_WEP_RESTRICT 81 -#define WLC_SET_WEP_RESTRICT 82 -#define WLC_GET_COUNTRY 83 -#define WLC_SET_COUNTRY 84 -#define WLC_GET_PM 85 -#define WLC_SET_PM 86 -#define WLC_GET_WAKE 87 -#define WLC_SET_WAKE 88 +#define WLC_LONGTRAIN 74 +#define WLC_GET_BCNPRD 75 +#define WLC_SET_BCNPRD 76 +#define WLC_GET_DTIMPRD 77 +#define WLC_SET_DTIMPRD 78 +#define WLC_GET_SROM 79 +#define WLC_SET_SROM 80 +#define WLC_GET_WEP_RESTRICT 81 +#define WLC_SET_WEP_RESTRICT 82 +#define WLC_GET_COUNTRY 83 +#define WLC_SET_COUNTRY 84 +#define WLC_GET_PM 85 +#define WLC_SET_PM 86 +#define WLC_GET_WAKE 87 +#define WLC_SET_WAKE 88 -#define WLC_GET_FORCELINK 90 -#define WLC_SET_FORCELINK 91 -#define WLC_FREQ_ACCURACY 92 -#define WLC_CARRIER_SUPPRESS 93 -#define WLC_GET_PHYREG 94 -#define WLC_SET_PHYREG 95 -#define WLC_GET_RADIOREG 96 -#define WLC_SET_RADIOREG 97 -#define WLC_GET_REVINFO 98 -#define WLC_GET_UCANTDIV 99 -#define WLC_SET_UCANTDIV 100 -#define WLC_R_REG 101 -#define WLC_W_REG 102 +#define WLC_GET_FORCELINK 90 +#define WLC_SET_FORCELINK 91 +#define WLC_FREQ_ACCURACY 92 +#define WLC_CARRIER_SUPPRESS 93 +#define WLC_GET_PHYREG 94 +#define WLC_SET_PHYREG 95 +#define WLC_GET_RADIOREG 96 +#define WLC_SET_RADIOREG 97 +#define WLC_GET_REVINFO 98 +#define WLC_GET_UCANTDIV 99 +#define WLC_SET_UCANTDIV 100 +#define WLC_R_REG 101 +#define WLC_W_REG 102 -#define WLC_GET_MACMODE 105 -#define WLC_SET_MACMODE 106 -#define WLC_GET_MONITOR 107 -#define WLC_SET_MONITOR 108 -#define WLC_GET_GMODE 109 -#define WLC_SET_GMODE 110 -#define WLC_GET_LEGACY_ERP 111 -#define WLC_SET_LEGACY_ERP 112 -#define WLC_GET_RX_ANT 113 -#define WLC_GET_CURR_RATESET 114 -#define WLC_GET_SCANSUPPRESS 115 -#define WLC_SET_SCANSUPPRESS 116 -#define WLC_GET_AP 117 -#define WLC_SET_AP 118 -#define WLC_GET_EAP_RESTRICT 119 -#define WLC_SET_EAP_RESTRICT 120 -#define WLC_SCB_AUTHORIZE 121 -#define WLC_SCB_DEAUTHORIZE 122 -#define WLC_GET_WDSLIST 123 -#define WLC_SET_WDSLIST 124 -#define WLC_GET_ATIM 125 -#define WLC_SET_ATIM 126 -#define WLC_GET_RSSI 127 -#define WLC_GET_PHYANTDIV 128 -#define WLC_SET_PHYANTDIV 129 -#define WLC_AP_RX_ONLY 130 -#define WLC_GET_TX_PATH_PWR 131 -#define WLC_SET_TX_PATH_PWR 132 -#define WLC_GET_WSEC 133 -#define WLC_SET_WSEC 134 -#define WLC_GET_PHY_NOISE 135 -#define WLC_GET_BSS_INFO 136 -#define WLC_GET_PKTCNTS 137 -#define WLC_GET_LAZYWDS 138 -#define WLC_SET_LAZYWDS 139 -#define WLC_GET_BANDLIST 140 -#define WLC_GET_BAND 141 -#define WLC_SET_BAND 142 -#define WLC_SCB_DEAUTHENTICATE 143 -#define WLC_GET_SHORTSLOT 144 -#define WLC_GET_SHORTSLOT_OVERRIDE 145 -#define WLC_SET_SHORTSLOT_OVERRIDE 146 -#define WLC_GET_SHORTSLOT_RESTRICT 147 -#define WLC_SET_SHORTSLOT_RESTRICT 148 -#define WLC_GET_GMODE_PROTECTION 149 -#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 -#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 -#define WLC_UPGRADE 152 +#define WLC_GET_MACMODE 105 +#define WLC_SET_MACMODE 106 +#define WLC_GET_MONITOR 107 +#define WLC_SET_MONITOR 108 +#define WLC_GET_GMODE 109 +#define WLC_SET_GMODE 110 +#define WLC_GET_LEGACY_ERP 111 +#define WLC_SET_LEGACY_ERP 112 +#define WLC_GET_RX_ANT 113 +#define WLC_GET_CURR_RATESET 114 +#define WLC_GET_SCANSUPPRESS 115 +#define WLC_SET_SCANSUPPRESS 116 +#define WLC_GET_AP 117 +#define WLC_SET_AP 118 +#define WLC_GET_EAP_RESTRICT 119 +#define WLC_SET_EAP_RESTRICT 120 +#define WLC_SCB_AUTHORIZE 121 +#define WLC_SCB_DEAUTHORIZE 122 +#define WLC_GET_WDSLIST 123 +#define WLC_SET_WDSLIST 124 +#define WLC_GET_ATIM 125 +#define WLC_SET_ATIM 126 +#define WLC_GET_RSSI 127 +#define WLC_GET_PHYANTDIV 128 +#define WLC_SET_PHYANTDIV 129 +#define WLC_AP_RX_ONLY 130 +#define WLC_GET_TX_PATH_PWR 131 +#define WLC_SET_TX_PATH_PWR 132 +#define WLC_GET_WSEC 133 +#define WLC_SET_WSEC 134 +#define WLC_GET_PHY_NOISE 135 +#define WLC_GET_BSS_INFO 136 +#define WLC_GET_PKTCNTS 137 +#define WLC_GET_LAZYWDS 138 +#define WLC_SET_LAZYWDS 139 +#define WLC_GET_BANDLIST 140 +#define WLC_GET_BAND 141 +#define WLC_SET_BAND 142 +#define WLC_SCB_DEAUTHENTICATE 143 +#define WLC_GET_SHORTSLOT 144 +#define WLC_GET_SHORTSLOT_OVERRIDE 145 +#define WLC_SET_SHORTSLOT_OVERRIDE 146 +#define WLC_GET_SHORTSLOT_RESTRICT 147 +#define WLC_SET_SHORTSLOT_RESTRICT 148 +#define WLC_GET_GMODE_PROTECTION 149 +#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 +#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 +#define WLC_UPGRADE 152 -#define WLC_GET_IGNORE_BCNS 155 -#define WLC_SET_IGNORE_BCNS 156 -#define WLC_GET_SCB_TIMEOUT 157 -#define WLC_SET_SCB_TIMEOUT 158 -#define WLC_GET_ASSOCLIST 159 -#define WLC_GET_CLK 160 -#define WLC_SET_CLK 161 -#define WLC_GET_UP 162 -#define WLC_OUT 163 -#define WLC_GET_WPA_AUTH 164 -#define WLC_SET_WPA_AUTH 165 -#define WLC_GET_UCFLAGS 166 -#define WLC_SET_UCFLAGS 167 -#define WLC_GET_PWRIDX 168 -#define WLC_SET_PWRIDX 169 -#define WLC_GET_TSSI 170 -#define WLC_GET_SUP_RATESET_OVERRIDE 171 -#define WLC_SET_SUP_RATESET_OVERRIDE 172 +#define WLC_GET_IGNORE_BCNS 155 +#define WLC_SET_IGNORE_BCNS 156 +#define WLC_GET_SCB_TIMEOUT 157 +#define WLC_SET_SCB_TIMEOUT 158 +#define WLC_GET_ASSOCLIST 159 +#define WLC_GET_CLK 160 +#define WLC_SET_CLK 161 +#define WLC_GET_UP 162 +#define WLC_OUT 163 +#define WLC_GET_WPA_AUTH 164 +#define WLC_SET_WPA_AUTH 165 +#define WLC_GET_UCFLAGS 166 +#define WLC_SET_UCFLAGS 167 +#define WLC_GET_PWRIDX 168 +#define WLC_SET_PWRIDX 169 +#define WLC_GET_TSSI 170 +#define WLC_GET_SUP_RATESET_OVERRIDE 171 +#define WLC_SET_SUP_RATESET_OVERRIDE 172 -#define WLC_GET_PROTECTION_CONTROL 178 -#define WLC_SET_PROTECTION_CONTROL 179 -#define WLC_GET_PHYLIST 180 -#define WLC_ENCRYPT_STRENGTH 181 -#define WLC_DECRYPT_STATUS 182 -#define WLC_GET_KEY_SEQ 183 -#define WLC_GET_SCAN_CHANNEL_TIME 184 -#define WLC_SET_SCAN_CHANNEL_TIME 185 -#define WLC_GET_SCAN_UNASSOC_TIME 186 -#define WLC_SET_SCAN_UNASSOC_TIME 187 -#define WLC_GET_SCAN_HOME_TIME 188 -#define WLC_SET_SCAN_HOME_TIME 189 -#define WLC_GET_SCAN_NPROBES 190 -#define WLC_SET_SCAN_NPROBES 191 -#define WLC_GET_PRB_RESP_TIMEOUT 192 -#define WLC_SET_PRB_RESP_TIMEOUT 193 -#define WLC_GET_ATTEN 194 -#define WLC_SET_ATTEN 195 -#define WLC_GET_SHMEM 196 -#define WLC_SET_SHMEM 197 +#define WLC_GET_PROTECTION_CONTROL 178 +#define WLC_SET_PROTECTION_CONTROL 179 +#define WLC_GET_PHYLIST 180 +#define WLC_ENCRYPT_STRENGTH 181 +#define WLC_DECRYPT_STATUS 182 +#define WLC_GET_KEY_SEQ 183 +#define WLC_GET_SCAN_CHANNEL_TIME 184 +#define WLC_SET_SCAN_CHANNEL_TIME 185 +#define WLC_GET_SCAN_UNASSOC_TIME 186 +#define WLC_SET_SCAN_UNASSOC_TIME 187 +#define WLC_GET_SCAN_HOME_TIME 188 +#define WLC_SET_SCAN_HOME_TIME 189 +#define WLC_GET_SCAN_NPROBES 190 +#define WLC_SET_SCAN_NPROBES 191 +#define WLC_GET_PRB_RESP_TIMEOUT 192 +#define WLC_SET_PRB_RESP_TIMEOUT 193 +#define WLC_GET_ATTEN 194 +#define WLC_SET_ATTEN 195 +#define WLC_GET_SHMEM 196 +#define WLC_SET_SHMEM 197 -#define WLC_SET_WSEC_TEST 200 -#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 -#define WLC_TKIP_COUNTERMEASURES 202 -#define WLC_GET_PIOMODE 203 -#define WLC_SET_PIOMODE 204 -#define WLC_SET_ASSOC_PREFER 205 -#define WLC_GET_ASSOC_PREFER 206 -#define WLC_SET_ROAM_PREFER 207 -#define WLC_GET_ROAM_PREFER 208 -#define WLC_SET_LED 209 -#define WLC_GET_LED 210 -#define WLC_GET_INTERFERENCE_MODE 211 -#define WLC_SET_INTERFERENCE_MODE 212 -#define WLC_GET_CHANNEL_QA 213 -#define WLC_START_CHANNEL_QA 214 -#define WLC_GET_CHANNEL_SEL 215 -#define WLC_START_CHANNEL_SEL 216 -#define WLC_GET_VALID_CHANNELS 217 -#define WLC_GET_FAKEFRAG 218 -#define WLC_SET_FAKEFRAG 219 -#define WLC_GET_PWROUT_PERCENTAGE 220 -#define WLC_SET_PWROUT_PERCENTAGE 221 -#define WLC_SET_BAD_FRAME_PREEMPT 222 -#define WLC_GET_BAD_FRAME_PREEMPT 223 -#define WLC_SET_LEAP_LIST 224 -#define WLC_GET_LEAP_LIST 225 -#define WLC_GET_CWMIN 226 -#define WLC_SET_CWMIN 227 -#define WLC_GET_CWMAX 228 -#define WLC_SET_CWMAX 229 -#define WLC_GET_WET 230 -#define WLC_SET_WET 231 -#define WLC_GET_PUB 232 +#define WLC_SET_WSEC_TEST 200 +#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define WLC_TKIP_COUNTERMEASURES 202 +#define WLC_GET_PIOMODE 203 +#define WLC_SET_PIOMODE 204 +#define WLC_SET_ASSOC_PREFER 205 +#define WLC_GET_ASSOC_PREFER 206 +#define WLC_SET_ROAM_PREFER 207 +#define WLC_GET_ROAM_PREFER 208 +#define WLC_SET_LED 209 +#define WLC_GET_LED 210 +#define WLC_GET_INTERFERENCE_MODE 211 +#define WLC_SET_INTERFERENCE_MODE 212 +#define WLC_GET_CHANNEL_QA 213 +#define WLC_START_CHANNEL_QA 214 +#define WLC_GET_CHANNEL_SEL 215 +#define WLC_START_CHANNEL_SEL 216 +#define WLC_GET_VALID_CHANNELS 217 +#define WLC_GET_FAKEFRAG 218 +#define WLC_SET_FAKEFRAG 219 +#define WLC_GET_PWROUT_PERCENTAGE 220 +#define WLC_SET_PWROUT_PERCENTAGE 221 +#define WLC_SET_BAD_FRAME_PREEMPT 222 +#define WLC_GET_BAD_FRAME_PREEMPT 223 +#define WLC_SET_LEAP_LIST 224 +#define WLC_GET_LEAP_LIST 225 +#define WLC_GET_CWMIN 226 +#define WLC_SET_CWMIN 227 +#define WLC_GET_CWMAX 228 +#define WLC_SET_CWMAX 229 +#define WLC_GET_WET 230 +#define WLC_SET_WET 231 +#define WLC_GET_PUB 232 -#define WLC_GET_KEY_PRIMARY 235 -#define WLC_SET_KEY_PRIMARY 236 +#define WLC_GET_KEY_PRIMARY 235 +#define WLC_SET_KEY_PRIMARY 236 -#define WLC_GET_ACI_ARGS 238 -#define WLC_SET_ACI_ARGS 239 -#define WLC_UNSET_CALLBACK 240 -#define WLC_SET_CALLBACK 241 -#define WLC_GET_RADAR 242 -#define WLC_SET_RADAR 243 -#define WLC_SET_SPECT_MANAGMENT 244 -#define WLC_GET_SPECT_MANAGMENT 245 -#define WLC_WDS_GET_REMOTE_HWADDR 246 -#define WLC_WDS_GET_WPA_SUP 247 -#define WLC_SET_CS_SCAN_TIMER 248 -#define WLC_GET_CS_SCAN_TIMER 249 -#define WLC_MEASURE_REQUEST 250 -#define WLC_INIT 251 -#define WLC_SEND_QUIET 252 -#define WLC_KEEPALIVE 253 -#define WLC_SEND_PWR_CONSTRAINT 254 -#define WLC_UPGRADE_STATUS 255 -#define WLC_CURRENT_PWR 256 -#define WLC_GET_SCAN_PASSIVE_TIME 257 -#define WLC_SET_SCAN_PASSIVE_TIME 258 -#define WLC_LEGACY_LINK_BEHAVIOR 259 -#define WLC_GET_CHANNELS_IN_COUNTRY 260 -#define WLC_GET_COUNTRY_LIST 261 -#define WLC_GET_VAR 262 -#define WLC_SET_VAR 263 -#define WLC_NVRAM_GET 264 -#define WLC_NVRAM_SET 265 -#define WLC_NVRAM_DUMP 266 -#define WLC_REBOOT 267 -#define WLC_SET_WSEC_PMK 268 -#define WLC_GET_AUTH_MODE 269 -#define WLC_SET_AUTH_MODE 270 -#define WLC_GET_WAKEENTRY 271 -#define WLC_SET_WAKEENTRY 272 -#define WLC_NDCONFIG_ITEM 273 -#define WLC_NVOTPW 274 -#define WLC_OTPW 275 -#define WLC_IOV_BLOCK_GET 276 -#define WLC_IOV_MODULES_GET 277 -#define WLC_SOFT_RESET 278 -#define WLC_GET_ALLOW_MODE 279 -#define WLC_SET_ALLOW_MODE 280 -#define WLC_GET_DESIRED_BSSID 281 -#define WLC_SET_DESIRED_BSSID 282 -#define WLC_DISASSOC_MYAP 283 -#define WLC_GET_NBANDS 284 -#define WLC_GET_BANDSTATES 285 -#define WLC_GET_WLC_BSS_INFO 286 -#define WLC_GET_ASSOC_INFO 287 -#define WLC_GET_OID_PHY 288 -#define WLC_SET_OID_PHY 289 -#define WLC_SET_ASSOC_TIME 290 -#define WLC_GET_DESIRED_SSID 291 -#define WLC_GET_CHANSPEC 292 -#define WLC_GET_ASSOC_STATE 293 -#define WLC_SET_PHY_STATE 294 -#define WLC_GET_SCAN_PENDING 295 -#define WLC_GET_SCANREQ_PENDING 296 -#define WLC_GET_PREV_ROAM_REASON 297 -#define WLC_SET_PREV_ROAM_REASON 298 -#define WLC_GET_BANDSTATES_PI 299 -#define WLC_GET_PHY_STATE 300 -#define WLC_GET_BSS_WPA_RSN 301 -#define WLC_GET_BSS_WPA2_RSN 302 -#define WLC_GET_BSS_BCN_TS 303 -#define WLC_GET_INT_DISASSOC 304 -#define WLC_SET_NUM_PEERS 305 -#define WLC_GET_NUM_BSS 306 -#define WLC_LAST 307 - - - -#define WL_AUTH_OPEN_SYSTEM 0 -#define WL_AUTH_SHARED_KEY 1 -#define WL_AUTH_OPEN_SHARED 2 - - -#define WL_RADIO_SW_DISABLE (1<<0) -#define WL_RADIO_HW_DISABLE (1<<1) -#define WL_RADIO_MPC_DISABLE (1<<2) -#define WL_RADIO_COUNTRY_DISABLE (1<<3) - - -#define WL_TXPWR_OVERRIDE (1<<31) - -#define WL_PHY_PAVARS_LEN 6 - - -#define WL_DIAG_INTERRUPT 1 -#define WL_DIAG_LOOPBACK 2 -#define WL_DIAG_MEMORY 3 -#define WL_DIAG_LED 4 -#define WL_DIAG_REG 5 -#define WL_DIAG_SROM 6 -#define WL_DIAG_DMA 7 - -#define WL_DIAGERR_SUCCESS 0 -#define WL_DIAGERR_FAIL_TO_RUN 1 -#define WL_DIAGERR_NOT_SUPPORTED 2 -#define WL_DIAGERR_INTERRUPT_FAIL 3 -#define WL_DIAGERR_LOOPBACK_FAIL 4 -#define WL_DIAGERR_SROM_FAIL 5 -#define WL_DIAGERR_SROM_BADCRC 6 -#define WL_DIAGERR_REG_FAIL 7 -#define WL_DIAGERR_MEMORY_FAIL 8 -#define WL_DIAGERR_NOMEM 9 -#define WL_DIAGERR_DMA_FAIL 10 - -#define WL_DIAGERR_MEMORY_TIMEOUT 11 -#define WL_DIAGERR_MEMORY_BADPATTERN 12 - - -#define WLC_BAND_AUTO 0 -#define WLC_BAND_5G 1 -#define WLC_BAND_2G 2 -#define WLC_BAND_ALL 3 - - -#define WL_CHAN_FREQ_RANGE_2G 0 -#define WL_CHAN_FREQ_RANGE_5GL 1 -#define WL_CHAN_FREQ_RANGE_5GM 2 -#define WL_CHAN_FREQ_RANGE_5GH 3 - - -#define WLC_PHY_TYPE_A 0 -#define WLC_PHY_TYPE_B 1 -#define WLC_PHY_TYPE_G 2 -#define WLC_PHY_TYPE_N 4 -#define WLC_PHY_TYPE_LP 5 -#define WLC_PHY_TYPE_NULL 0xf - - -#define WLC_MACMODE_DISABLED 0 -#define WLC_MACMODE_DENY 1 -#define WLC_MACMODE_ALLOW 2 - - -#define GMODE_LEGACY_B 0 -#define GMODE_AUTO 1 -#define GMODE_ONLY 2 -#define GMODE_B_DEFERRED 3 -#define GMODE_PERFORMANCE 4 -#define GMODE_LRS 5 -#define GMODE_MAX 6 +#define WLC_GET_ACI_ARGS 238 +#define WLC_SET_ACI_ARGS 239 +#define WLC_UNSET_CALLBACK 240 +#define WLC_SET_CALLBACK 241 +#define WLC_GET_RADAR 242 +#define WLC_SET_RADAR 243 +#define WLC_SET_SPECT_MANAGMENT 244 +#define WLC_GET_SPECT_MANAGMENT 245 +#define WLC_WDS_GET_REMOTE_HWADDR 246 +#define WLC_WDS_GET_WPA_SUP 247 +#define WLC_SET_CS_SCAN_TIMER 248 +#define WLC_GET_CS_SCAN_TIMER 249 +#define WLC_MEASURE_REQUEST 250 +#define WLC_INIT 251 +#define WLC_SEND_QUIET 252 +#define WLC_KEEPALIVE 253 +#define WLC_SEND_PWR_CONSTRAINT 254 +#define WLC_UPGRADE_STATUS 255 +#define WLC_CURRENT_PWR 256 +#define WLC_GET_SCAN_PASSIVE_TIME 257 +#define WLC_SET_SCAN_PASSIVE_TIME 258 +#define WLC_LEGACY_LINK_BEHAVIOR 259 +#define WLC_GET_CHANNELS_IN_COUNTRY 260 +#define WLC_GET_COUNTRY_LIST 261 +#define WLC_GET_VAR 262 +#define WLC_SET_VAR 263 +#define WLC_NVRAM_GET 264 +#define WLC_NVRAM_SET 265 +#define WLC_NVRAM_DUMP 266 +#define WLC_REBOOT 267 +#define WLC_SET_WSEC_PMK 268 +#define WLC_GET_AUTH_MODE 269 +#define WLC_SET_AUTH_MODE 270 +#define WLC_GET_WAKEENTRY 271 +#define WLC_SET_WAKEENTRY 272 +#define WLC_NDCONFIG_ITEM 273 +#define WLC_NVOTPW 274 +#define WLC_OTPW 275 +#define WLC_IOV_BLOCK_GET 276 +#define WLC_IOV_MODULES_GET 277 +#define WLC_SOFT_RESET 278 +#define WLC_GET_ALLOW_MODE 279 +#define WLC_SET_ALLOW_MODE 280 +#define WLC_GET_DESIRED_BSSID 281 +#define WLC_SET_DESIRED_BSSID 282 +#define WLC_DISASSOC_MYAP 283 +#define WLC_GET_NBANDS 284 +#define WLC_GET_BANDSTATES 285 +#define WLC_GET_WLC_BSS_INFO 286 +#define WLC_GET_ASSOC_INFO 287 +#define WLC_GET_OID_PHY 288 +#define WLC_SET_OID_PHY 289 +#define WLC_SET_ASSOC_TIME 290 +#define WLC_GET_DESIRED_SSID 291 +#define WLC_GET_CHANSPEC 292 +#define WLC_GET_ASSOC_STATE 293 +#define WLC_SET_PHY_STATE 294 +#define WLC_GET_SCAN_PENDING 295 +#define WLC_GET_SCANREQ_PENDING 296 +#define WLC_GET_PREV_ROAM_REASON 297 +#define WLC_SET_PREV_ROAM_REASON 298 +#define WLC_GET_BANDSTATES_PI 299 +#define WLC_GET_PHY_STATE 300 +#define WLC_GET_BSS_WPA_RSN 301 +#define WLC_GET_BSS_WPA2_RSN 302 +#define WLC_GET_BSS_BCN_TS 303 +#define WLC_GET_INT_DISASSOC 304 +#define WLC_SET_NUM_PEERS 305 +#define WLC_GET_NUM_BSS 306 +#define WLC_NPHY_SAMPLE_COLLECT 307 +#define WLC_UM_PRIV 308 +#define WLC_GET_CMD 309 + +#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 +#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 +#define WLC_GET_WAI_RESTRICT 313 +#define WLC_SET_WAI_RESTRICT 314 +#define WLC_SET_WAI_REKEY 315 +#define WLC_SET_PEAKRATE 316 +#define WLC_GET_PEAKRATE 317 +#define WLC_LAST 318 + +#ifndef EPICTRL_COOKIE +#define EPICTRL_COOKIE 0xABADCEDE +#endif + + +#define CMN_IOCTL_OFF 0x180 + + + + +#define WL_OID_BASE 0xFFE41420 + + +#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) +#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) +#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) +#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) +#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) +#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) +#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) + + +#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) +#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) +#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) +#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) +#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) +#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) +#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) +#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) +#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) +#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) +#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) +#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) +#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) +#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) +#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) + +#define WL_DECRYPT_STATUS_SUCCESS 1 +#define WL_DECRYPT_STATUS_FAILURE 2 +#define WL_DECRYPT_STATUS_UNKNOWN 3 + + +#define WLC_UPGRADE_SUCCESS 0 +#define WLC_UPGRADE_PENDING 1 + +#ifdef CONFIG_USBRNDIS_RETAIL +typedef struct { + char *name; + void *param; +} ndconfig_item_t; +#endif -#define WLC_PLCP_AUTO -1 -#define WLC_PLCP_SHORT 0 -#define WLC_PLCP_LONG 1 -#define WLC_PROTECTION_AUTO -1 -#define WLC_PROTECTION_OFF 0 -#define WLC_PROTECTION_ON 1 -#define WLC_PROTECTION_MMHDR_ONLY 2 -#define WLC_PROTECTION_CTS_ONLY 3 +#define WL_AUTH_OPEN_SYSTEM 0 +#define WL_AUTH_SHARED_KEY 1 +#define WL_AUTH_OPEN_SHARED 2 -#define WLC_PROTECTION_CTL_OFF 0 -#define WLC_PROTECTION_CTL_LOCAL 1 -#define WLC_PROTECTION_CTL_OVERLAP 2 +#define WL_RADIO_SW_DISABLE (1<<0) +#define WL_RADIO_HW_DISABLE (1<<1) +#define WL_RADIO_MPC_DISABLE (1<<2) +#define WL_RADIO_COUNTRY_DISABLE (1<<3) +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 -#define WLC_N_PROTECTION_OFF 0 -#define WLC_N_PROTECTION_OPTIONAL 1 -#define WLC_N_PROTECTION_20IN40 2 -#define WLC_N_PROTECTION_MIXEDMODE 3 +#define WL_TXPWR_OVERRIDE (1U<<31) +#define WL_TXPWR_NEG (1U<<30) -#define WLC_N_PREAMBLE_MIXEDMODE 0 -#define WLC_N_PREAMBLE_GF 1 +#define WL_PHY_PAVARS_LEN 6 +#define WL_PHY_PAVARS2_NUM 3 +#define WL_PHY_PAVAR_VER 1 +typedef struct wl_pavars2 { + uint16 ver; + uint16 len; + uint16 inuse; + uint16 phy_type; + uint16 bandrange; + uint16 chain; + uint16 inpa[WL_PHY_PAVARS2_NUM]; +} wl_pavars2_t; -#define WLC_N_BW_20ALL 0 -#define WLC_N_BW_40ALL 1 -#define WLC_N_BW_20IN2G_40IN5G 2 +typedef struct wl_po { + uint16 phy_type; + uint16 band; + uint16 cckpo; + uint32 ofdmpo; + uint16 mcspo[8]; +} wl_po_t; -#define WLC_N_TXRX_CHAIN0 0 -#define WLC_N_TXRX_CHAIN1 1 +#define WLC_TXPWR_MAX (127) -#define WLC_N_SGI_20 0x01 -#define WLC_N_SGI_40 0x02 +#define WL_DIAG_INTERRUPT 1 +#define WL_DIAG_LOOPBACK 2 +#define WL_DIAG_MEMORY 3 +#define WL_DIAG_LED 4 +#define WL_DIAG_REG 5 +#define WL_DIAG_SROM 6 +#define WL_DIAG_DMA 7 +#define WL_DIAGERR_SUCCESS 0 +#define WL_DIAGERR_FAIL_TO_RUN 1 +#define WL_DIAGERR_NOT_SUPPORTED 2 +#define WL_DIAGERR_INTERRUPT_FAIL 3 +#define WL_DIAGERR_LOOPBACK_FAIL 4 +#define WL_DIAGERR_SROM_FAIL 5 +#define WL_DIAGERR_SROM_BADCRC 6 +#define WL_DIAGERR_REG_FAIL 7 +#define WL_DIAGERR_MEMORY_FAIL 8 +#define WL_DIAGERR_NOMEM 9 +#define WL_DIAGERR_DMA_FAIL 10 -#define PM_OFF 0 -#define PM_MAX 1 -#define PM_FAST 2 +#define WL_DIAGERR_MEMORY_TIMEOUT 11 +#define WL_DIAGERR_MEMORY_BADPATTERN 12 -#define INTERFERE_NONE 0 -#define NON_WLAN 1 -#define WLAN_MANUAL 2 -#define WLAN_AUTO 3 -#define AUTO_ACTIVE (1 << 7) +#define WLC_BAND_AUTO 0 +#define WLC_BAND_5G 1 +#define WLC_BAND_2G 2 +#define WLC_BAND_ALL 3 -typedef struct wl_aci_args { - int enter_aci_thresh; - int exit_aci_thresh; - int usec_spin; - int glitch_delay; - uint16 nphy_adcpwr_enter_thresh; - uint16 nphy_adcpwr_exit_thresh; - uint16 nphy_repeat_ctr; - uint16 nphy_num_samples; - uint16 nphy_undetect_window_sz; - uint16 nphy_b_energy_lo_aci; - uint16 nphy_b_energy_md_aci; - uint16 nphy_b_energy_hi_aci; -} wl_aci_args_t; - - -#define WL_ACI_ARGS_LEGACY_LENGTH 16 - - - -#define WL_ERROR_VAL 0x00000001 -#define WL_TRACE_VAL 0x00000002 -#define WL_PRHDRS_VAL 0x00000004 -#define WL_PRPKT_VAL 0x00000008 -#define WL_INFORM_VAL 0x00000010 -#define WL_TMP_VAL 0x00000020 -#define WL_OID_VAL 0x00000040 -#define WL_RATE_VAL 0x00000080 -#define WL_ASSOC_VAL 0x00000100 -#define WL_PRUSR_VAL 0x00000200 -#define WL_PS_VAL 0x00000400 -#define WL_TXPWR_VAL 0x00000800 -#define WL_PORT_VAL 0x00001000 -#define WL_DUAL_VAL 0x00002000 -#define WL_WSEC_VAL 0x00004000 -#define WL_WSEC_DUMP_VAL 0x00008000 -#define WL_LOG_VAL 0x00010000 -#define WL_NRSSI_VAL 0x00020000 -#define WL_LOFT_VAL 0x00040000 -#define WL_REGULATORY_VAL 0x00080000 -#define WL_PHYCAL_VAL 0x00100000 -#define WL_RADAR_VAL 0x00200000 -#define WL_MPC_VAL 0x00400000 -#define WL_APSTA_VAL 0x00800000 -#define WL_DFS_VAL 0x01000000 -#define WL_BA_VAL 0x02000000 -#define WL_MBSS_VAL 0x04000000 -#define WL_CAC_VAL 0x08000000 -#define WL_AMSDU_VAL 0x10000000 -#define WL_AMPDU_VAL 0x20000000 -#define WL_FFPLD_VAL 0x40000000 - - -#define WL_DPT_VAL 0x00000001 -#define WL_SCAN_VAL 0x00000002 -#define WL_WOWL_VAL 0x00000004 -#define WL_COEX_VAL 0x00000008 -#define WL_RTDC_VAL 0x00000010 -#define WL_BTA_VAL 0x00000040 +#define WL_CHAN_FREQ_RANGE_2G 0 +#define WL_CHAN_FREQ_RANGE_5GL 1 +#define WL_CHAN_FREQ_RANGE_5GM 2 +#define WL_CHAN_FREQ_RANGE_5GH 3 +#define WL_CHAN_FREQ_RANGE_5GLL_VER2 4 +#define WL_CHAN_FREQ_RANGE_5GLH_VER2 5 +#define WL_CHAN_FREQ_RANGE_5GML_VER2 6 +#define WL_CHAN_FREQ_RANGE_5GMH_VER2 7 +#define WL_CHAN_FREQ_RANGE_5GH_VER2 8 -#define WL_LED_NUMGPIO 16 +#define WLC_PHY_TYPE_A 0 +#define WLC_PHY_TYPE_B 1 +#define WLC_PHY_TYPE_G 2 +#define WLC_PHY_TYPE_N 4 +#define WLC_PHY_TYPE_LP 5 +#define WLC_PHY_TYPE_SSN 6 +#define WLC_PHY_TYPE_HT 7 +#define WLC_PHY_TYPE_LCN 8 +#define WLC_PHY_TYPE_NULL 0xf -#define WL_LED_OFF 0 -#define WL_LED_ON 1 -#define WL_LED_ACTIVITY 2 -#define WL_LED_RADIO 3 -#define WL_LED_ARADIO 4 -#define WL_LED_BRADIO 5 -#define WL_LED_BGMODE 6 -#define WL_LED_WI1 7 -#define WL_LED_WI2 8 -#define WL_LED_WI3 9 -#define WL_LED_ASSOC 10 -#define WL_LED_INACTIVE 11 -#define WL_LED_ASSOCACT 12 -#define WL_LED_NUMBEHAVIOR 13 +#define WLC_MACMODE_DISABLED 0 +#define WLC_MACMODE_DENY 1 +#define WLC_MACMODE_ALLOW 2 -#define WL_LED_BEH_MASK 0x7f -#define WL_LED_AL_MASK 0x80 +#define GMODE_LEGACY_B 0 +#define GMODE_AUTO 1 +#define GMODE_ONLY 2 +#define GMODE_B_DEFERRED 3 +#define GMODE_PERFORMANCE 4 +#define GMODE_LRS 5 +#define GMODE_MAX 6 -#define WL_NUMCHANNELS 64 -#define WL_NUMCHANSPECS 100 +#define WLC_PLCP_AUTO -1 +#define WLC_PLCP_SHORT 0 +#define WLC_PLCP_LONG 1 -#define WL_WDS_WPA_ROLE_AUTH 0 -#define WL_WDS_WPA_ROLE_SUP 1 -#define WL_WDS_WPA_ROLE_AUTO 255 +#define WLC_PROTECTION_AUTO -1 +#define WLC_PROTECTION_OFF 0 +#define WLC_PROTECTION_ON 1 +#define WLC_PROTECTION_MMHDR_ONLY 2 +#define WLC_PROTECTION_CTS_ONLY 3 -#define WL_EVENTING_MASK_LEN 16 +#define WLC_PROTECTION_CTL_OFF 0 +#define WLC_PROTECTION_CTL_LOCAL 1 +#define WLC_PROTECTION_CTL_OVERLAP 2 -#define VNDR_IE_CMD_LEN 4 +#define WLC_N_PROTECTION_OFF 0 +#define WLC_N_PROTECTION_OPTIONAL 1 +#define WLC_N_PROTECTION_20IN40 2 +#define WLC_N_PROTECTION_MIXEDMODE 3 -#define VNDR_IE_BEACON_FLAG 0x1 -#define VNDR_IE_PRBRSP_FLAG 0x2 -#define VNDR_IE_ASSOCRSP_FLAG 0x4 -#define VNDR_IE_AUTHRSP_FLAG 0x8 -#define VNDR_IE_PRBREQ_FLAG 0x10 -#define VNDR_IE_ASSOCREQ_FLAG 0x20 -#define VNDR_IE_CUSTOM_FLAG 0x100 -#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) +#define WLC_N_PREAMBLE_MIXEDMODE 0 +#define WLC_N_PREAMBLE_GF 1 +#define WLC_N_PREAMBLE_GF_BRCM 2 -typedef struct { - uint32 pktflag; - vndr_ie_t vndr_ie_data; -} vndr_ie_info_t; -typedef struct { - int iecount; - vndr_ie_info_t vndr_ie_list[1]; -} vndr_ie_buf_t; +#define WLC_N_BW_20ALL 0 +#define WLC_N_BW_40ALL 1 +#define WLC_N_BW_20IN2G_40IN5G 2 -typedef struct { - char cmd[VNDR_IE_CMD_LEN]; - vndr_ie_buf_t vndr_ie_buffer; -} vndr_ie_setbuf_t; +#define WLC_N_TXRX_CHAIN0 0 +#define WLC_N_TXRX_CHAIN1 1 +#define WLC_N_SGI_20 0x01 +#define WLC_N_SGI_40 0x02 -#define WL_JOIN_PREF_RSSI 1 -#define WL_JOIN_PREF_WPA 2 -#define WL_JOIN_PREF_BAND 3 -#define WL_JOIN_PREF_RSSI_DELTA 4 +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 +#define LISTEN_INTERVAL 20 -#define WLJP_BAND_ASSOC_PREF 255 +#define INTERFERE_OVRRIDE_OFF -1 +#define INTERFERE_NONE 0 +#define NON_WLAN 1 +#define WLAN_MANUAL 2 +#define WLAN_AUTO 3 +#define WLAN_AUTO_W_NOISE 4 +#define AUTO_ACTIVE (1 << 7) +typedef struct wl_aci_args { + int enter_aci_thresh; + int exit_aci_thresh; + int usec_spin; + int glitch_delay; + uint16 nphy_adcpwr_enter_thresh; + uint16 nphy_adcpwr_exit_thresh; + uint16 nphy_repeat_ctr; + uint16 nphy_num_samples; + uint16 nphy_undetect_window_sz; + uint16 nphy_b_energy_lo_aci; + uint16 nphy_b_energy_md_aci; + uint16 nphy_b_energy_hi_aci; + uint16 nphy_noise_noassoc_glitch_th_up; + uint16 nphy_noise_noassoc_glitch_th_dn; + uint16 nphy_noise_assoc_glitch_th_up; + uint16 nphy_noise_assoc_glitch_th_dn; + uint16 nphy_noise_assoc_aci_glitch_th_up; + uint16 nphy_noise_assoc_aci_glitch_th_dn; + uint16 nphy_noise_assoc_enter_th; + uint16 nphy_noise_noassoc_enter_th; + uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; + uint16 nphy_noise_noassoc_crsidx_incr; + uint16 nphy_noise_assoc_crsidx_incr; + uint16 nphy_noise_crsidx_decr; +} wl_aci_args_t; -#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" +#define TRIGGER_NOW 0 +#define TRIGGER_CRS 0x01 +#define TRIGGER_CRSDEASSERT 0x02 +#define TRIGGER_GOODFCS 0x04 +#define TRIGGER_BADFCS 0x08 +#define TRIGGER_BADPLCP 0x10 +#define TRIGGER_CRSGLITCH 0x20 +#define WL_ACI_ARGS_LEGACY_LENGTH 16 +#define WL_SAMPLECOLLECT_T_VERSION 1 +typedef struct wl_samplecollect_args { + + uint8 coll_us; + int cores; + + uint16 version; + uint16 length; + uint8 trigger; + uint16 timeout; + uint16 mode; + uint32 pre_dur; + uint32 post_dur; + uint8 gpio_sel; + bool downsamp; + bool be_deaf; + bool agc; + bool filter; +} wl_samplecollect_args_t; + +#define WL_SAMPLEDATA_HEADER_TYPE 1 +#define WL_SAMPLEDATA_HEADER_SIZE 80 +#define WL_SAMPLEDATA_TYPE 2 +#define WL_SAMPLEDATA_SEQ 0xff +#define WL_SAMPLEDATA_MORE_DATA 0x100 +#define WL_SAMPLEDATA_T_VERSION 1 + +#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 + +typedef struct wl_sampledata { + uint16 version; + uint16 size; + uint16 tag; + uint16 length; + uint32 flag; +} wl_sampledata_t; + + + +#define WL_ERROR_VAL 0x00000001 +#define WL_TRACE_VAL 0x00000002 +#define WL_PRHDRS_VAL 0x00000004 +#define WL_PRPKT_VAL 0x00000008 +#define WL_INFORM_VAL 0x00000010 +#define WL_TMP_VAL 0x00000020 +#define WL_OID_VAL 0x00000040 +#define WL_RATE_VAL 0x00000080 +#define WL_ASSOC_VAL 0x00000100 +#define WL_PRUSR_VAL 0x00000200 +#define WL_PS_VAL 0x00000400 +#define WL_TXPWR_VAL 0x00000800 +#define WL_PORT_VAL 0x00001000 +#define WL_DUAL_VAL 0x00002000 +#define WL_WSEC_VAL 0x00004000 +#define WL_WSEC_DUMP_VAL 0x00008000 +#define WL_LOG_VAL 0x00010000 +#define WL_NRSSI_VAL 0x00020000 +#define WL_LOFT_VAL 0x00040000 +#define WL_REGULATORY_VAL 0x00080000 +#define WL_PHYCAL_VAL 0x00100000 +#define WL_RADAR_VAL 0x00200000 +#define WL_MPC_VAL 0x00400000 +#define WL_APSTA_VAL 0x00800000 +#define WL_DFS_VAL 0x01000000 +#define WL_BA_VAL 0x02000000 +#define WL_ACI_VAL 0x04000000 +#define WL_MBSS_VAL 0x04000000 +#define WL_CAC_VAL 0x08000000 +#define WL_AMSDU_VAL 0x10000000 +#define WL_AMPDU_VAL 0x20000000 +#define WL_FFPLD_VAL 0x40000000 + + +#define WL_DPT_VAL 0x00000001 +#define WL_SCAN_VAL 0x00000002 +#define WL_WOWL_VAL 0x00000004 +#define WL_COEX_VAL 0x00000008 +#define WL_RTDC_VAL 0x00000010 +#define WL_PROTO_VAL 0x00000020 +#define WL_BTA_VAL 0x00000040 +#define WL_CHANINT_VAL 0x00000080 +#define WL_THERMAL_VAL 0x00000100 +#define WL_P2P_VAL 0x00000200 +#define WL_TXRX_VAL 0x00000400 +#define WL_MCHAN_VAL 0x00000800 + + +#define WL_LED_NUMGPIO 16 + + +#define WL_LED_OFF 0 +#define WL_LED_ON 1 +#define WL_LED_ACTIVITY 2 +#define WL_LED_RADIO 3 +#define WL_LED_ARADIO 4 +#define WL_LED_BRADIO 5 +#define WL_LED_BGMODE 6 +#define WL_LED_WI1 7 +#define WL_LED_WI2 8 +#define WL_LED_WI3 9 +#define WL_LED_ASSOC 10 +#define WL_LED_INACTIVE 11 +#define WL_LED_ASSOCACT 12 +#define WL_LED_WI4 13 +#define WL_LED_WI5 14 +#define WL_LED_BLINKSLOW 15 +#define WL_LED_BLINKMED 16 +#define WL_LED_BLINKFAST 17 +#define WL_LED_BLINKCUSTOM 18 +#define WL_LED_BLINKPERIODIC 19 +#define WL_LED_ASSOC_WITH_SEC 20 + +#define WL_LED_START_OFF 21 +#define WL_LED_NUMBEHAVIOR 22 + + +#define WL_LED_BEH_MASK 0x7f +#define WL_LED_AL_MASK 0x80 + + +#define WL_NUMCHANNELS 64 +#define WL_NUMCHANSPECS 100 + + +#define WL_WDS_WPA_ROLE_AUTH 0 +#define WL_WDS_WPA_ROLE_SUP 1 +#define WL_WDS_WPA_ROLE_AUTO 255 + + +#define WL_EVENTING_MASK_LEN 16 + + + + +#define WL_JOIN_PREF_RSSI 1 +#define WL_JOIN_PREF_WPA 2 +#define WL_JOIN_PREF_BAND 3 +#define WL_JOIN_PREF_RSSI_DELTA 4 + + +#define WLJP_BAND_ASSOC_PREF 255 + + +#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" struct tsinfo_arg { uint8 octets[3]; }; +#define NFIFO 6 -#define NFIFO 6 - -#define WL_CNT_T_VERSION 5 -#define WL_CNT_EXT_T_VERSION 1 +#define WL_CNT_T_VERSION 6 typedef struct { - uint16 version; - uint16 length; + uint16 version; + uint16 length; - uint32 txframe; - uint32 txbyte; - uint32 txretrans; - uint32 txerror; - uint32 txctl; - uint32 txprshort; - uint32 txserr; - uint32 txnobuf; - uint32 txnoassoc; - uint32 txrunt; - uint32 txchit; - uint32 txcmiss; + uint32 txframe; + uint32 txbyte; + uint32 txretrans; + uint32 txerror; + uint32 txctl; + uint32 txprshort; + uint32 txserr; + uint32 txnobuf; + uint32 txnoassoc; + uint32 txrunt; + uint32 txchit; + uint32 txcmiss; - uint32 txuflo; - uint32 txphyerr; - uint32 txphycrs; + uint32 txuflo; + uint32 txphyerr; + uint32 txphycrs; - uint32 rxframe; - uint32 rxbyte; - uint32 rxerror; - uint32 rxctl; - uint32 rxnobuf; - uint32 rxnondata; - uint32 rxbadds; - uint32 rxbadcm; - uint32 rxfragerr; - uint32 rxrunt; - uint32 rxgiant; - uint32 rxnoscb; - uint32 rxbadproto; - uint32 rxbadsrcmac; - uint32 rxbadda; - uint32 rxfilter; + uint32 rxframe; + uint32 rxbyte; + uint32 rxerror; + uint32 rxctl; + uint32 rxnobuf; + uint32 rxnondata; + uint32 rxbadds; + uint32 rxbadcm; + uint32 rxfragerr; + uint32 rxrunt; + uint32 rxgiant; + uint32 rxnoscb; + uint32 rxbadproto; + uint32 rxbadsrcmac; + uint32 rxbadda; + uint32 rxfilter; - uint32 rxoflo; - uint32 rxuflo[NFIFO]; + uint32 rxoflo; + uint32 rxuflo[NFIFO]; - uint32 d11cnt_txrts_off; - uint32 d11cnt_rxcrc_off; - uint32 d11cnt_txnocts_off; + uint32 d11cnt_txrts_off; + uint32 d11cnt_rxcrc_off; + uint32 d11cnt_txnocts_off; - uint32 dmade; - uint32 dmada; - uint32 dmape; - uint32 reset; - uint32 tbtt; - uint32 txdmawar; - uint32 pkt_callback_reg_fail; + uint32 dmade; + uint32 dmada; + uint32 dmape; + uint32 reset; + uint32 tbtt; + uint32 txdmawar; + uint32 pkt_callback_reg_fail; - uint32 txallfrm; - uint32 txrtsfrm; - uint32 txctsfrm; - uint32 txackfrm; - uint32 txdnlfrm; - uint32 txbcnfrm; - uint32 txfunfl[8]; - uint32 txtplunfl; - uint32 txphyerror; - uint32 rxfrmtoolong; - uint32 rxfrmtooshrt; - uint32 rxinvmachdr; - uint32 rxbadfcs; - uint32 rxbadplcp; - uint32 rxcrsglitch; - uint32 rxstrt; - uint32 rxdfrmucastmbss; - uint32 rxmfrmucastmbss; - uint32 rxcfrmucast; - uint32 rxrtsucast; - uint32 rxctsucast; - uint32 rxackucast; - uint32 rxdfrmocast; - uint32 rxmfrmocast; - uint32 rxcfrmocast; - uint32 rxrtsocast; - uint32 rxctsocast; - uint32 rxdfrmmcast; - uint32 rxmfrmmcast; - uint32 rxcfrmmcast; - uint32 rxbeaconmbss; - uint32 rxdfrmucastobss; - uint32 rxbeaconobss; - uint32 rxrsptmout; - uint32 bcntxcancl; - uint32 rxf0ovfl; - uint32 rxf1ovfl; - uint32 rxf2ovfl; - uint32 txsfovfl; - uint32 pmqovfl; - uint32 rxcgprqfrm; - uint32 rxcgprsqovfl; - uint32 txcgprsfail; - uint32 txcgprssuc; - uint32 prs_timeout; - uint32 rxnack; - uint32 frmscons; - uint32 txnack; - uint32 txglitch_nack; - uint32 txburst; + uint32 txallfrm; + uint32 txrtsfrm; + uint32 txctsfrm; + uint32 txackfrm; + uint32 txdnlfrm; + uint32 txbcnfrm; + uint32 txfunfl[8]; + uint32 txtplunfl; + uint32 txphyerror; + uint32 rxfrmtoolong; + uint32 rxfrmtooshrt; + uint32 rxinvmachdr; + uint32 rxbadfcs; + uint32 rxbadplcp; + uint32 rxcrsglitch; + uint32 rxstrt; + uint32 rxdfrmucastmbss; + uint32 rxmfrmucastmbss; + uint32 rxcfrmucast; + uint32 rxrtsucast; + uint32 rxctsucast; + uint32 rxackucast; + uint32 rxdfrmocast; + uint32 rxmfrmocast; + uint32 rxcfrmocast; + uint32 rxrtsocast; + uint32 rxctsocast; + uint32 rxdfrmmcast; + uint32 rxmfrmmcast; + uint32 rxcfrmmcast; + uint32 rxbeaconmbss; + uint32 rxdfrmucastobss; + uint32 rxbeaconobss; + uint32 rxrsptmout; + uint32 bcntxcancl; + uint32 rxf0ovfl; + uint32 rxf1ovfl; + uint32 rxf2ovfl; + uint32 txsfovfl; + uint32 pmqovfl; + uint32 rxcgprqfrm; + uint32 rxcgprsqovfl; + uint32 txcgprsfail; + uint32 txcgprssuc; + uint32 prs_timeout; + uint32 rxnack; + uint32 frmscons; + uint32 txnack; + uint32 txglitch_nack; + uint32 txburst; - uint32 txfrag; - uint32 txmulti; - uint32 txfail; - uint32 txretry; - uint32 txretrie; - uint32 rxdup; - uint32 txrts; - uint32 txnocts; - uint32 txnoack; - uint32 rxfrag; - uint32 rxmulti; - uint32 rxcrc; - uint32 txfrmsnt; - uint32 rxundec; + uint32 txfrag; + uint32 txmulti; + uint32 txfail; + uint32 txretry; + uint32 txretrie; + uint32 rxdup; + uint32 txrts; + uint32 txnocts; + uint32 txnoack; + uint32 rxfrag; + uint32 rxmulti; + uint32 rxcrc; + uint32 txfrmsnt; + uint32 rxundec; - uint32 tkipmicfaill; - uint32 tkipcntrmsr; - uint32 tkipreplay; - uint32 ccmpfmterr; - uint32 ccmpreplay; - uint32 ccmpundec; - uint32 fourwayfail; - uint32 wepundec; - uint32 wepicverr; - uint32 decsuccess; - uint32 tkipicverr; - uint32 wepexcluded; - - uint32 txchanrej; - uint32 psmwds; - uint32 phywatchdog; + uint32 tkipmicfaill; + uint32 tkipcntrmsr; + uint32 tkipreplay; + uint32 ccmpfmterr; + uint32 ccmpreplay; + uint32 ccmpundec; + uint32 fourwayfail; + uint32 wepundec; + uint32 wepicverr; + uint32 decsuccess; + uint32 tkipicverr; + uint32 wepexcluded; + + uint32 rxundec_mcst; - uint32 prq_entries_handled; - uint32 prq_undirected_entries; - uint32 prq_bad_entries; - uint32 atim_suppress_count; - uint32 bcn_template_not_ready; - uint32 bcn_template_not_ready_done; - uint32 late_tbtt_dpc; + uint32 tkipmicfaill_mcst; + uint32 tkipcntrmsr_mcst; + uint32 tkipreplay_mcst; + uint32 ccmpfmterr_mcst; + uint32 ccmpreplay_mcst; + uint32 ccmpundec_mcst; + uint32 fourwayfail_mcst; + uint32 wepundec_mcst; + uint32 wepicverr_mcst; + uint32 decsuccess_mcst; + uint32 tkipicverr_mcst; + uint32 wepexcluded_mcst; + + uint32 txchanrej; + uint32 txexptime; + uint32 psmwds; + uint32 phywatchdog; - uint32 rx1mbps; - uint32 rx2mbps; - uint32 rx5mbps5; - uint32 rx6mbps; - uint32 rx9mbps; - uint32 rx11mbps; - uint32 rx12mbps; - uint32 rx18mbps; - uint32 rx24mbps; - uint32 rx36mbps; - uint32 rx48mbps; - uint32 rx54mbps; - uint32 rx108mbps; - uint32 rx162mbps; - uint32 rx216mbps; - uint32 rx270mbps; - uint32 rx324mbps; - uint32 rx378mbps; - uint32 rx432mbps; - uint32 rx486mbps; - uint32 rx540mbps; + uint32 prq_entries_handled; + uint32 prq_undirected_entries; + uint32 prq_bad_entries; + uint32 atim_suppress_count; + uint32 bcn_template_not_ready; + uint32 bcn_template_not_ready_done; + uint32 late_tbtt_dpc; - uint32 pktengrxducast; - uint32 pktengrxdmcast; -} wl_cnt_t; + uint32 rx1mbps; + uint32 rx2mbps; + uint32 rx5mbps5; + uint32 rx6mbps; + uint32 rx9mbps; + uint32 rx11mbps; + uint32 rx12mbps; + uint32 rx18mbps; + uint32 rx24mbps; + uint32 rx36mbps; + uint32 rx48mbps; + uint32 rx54mbps; + uint32 rx108mbps; + uint32 rx162mbps; + uint32 rx216mbps; + uint32 rx270mbps; + uint32 rx324mbps; + uint32 rx378mbps; + uint32 rx432mbps; + uint32 rx486mbps; + uint32 rx540mbps; -#define WL_DELTA_STATS_T_VERSION 1 + + uint32 pktengrxducast; + uint32 pktengrxdmcast; -typedef struct { - uint16 version; - uint16 length; + uint32 rfdisable; + uint32 bphy_rxcrsglitch; - - uint32 txframe; - uint32 txbyte; - uint32 txretrans; - uint32 txfail; + uint32 txmpdu_sgi; + uint32 rxmpdu_sgi; + uint32 txmpdu_stbc; + uint32 rxmpdu_stbc; +} wl_cnt_t; - - uint32 rxframe; - uint32 rxbyte; - - uint32 rx1mbps; - uint32 rx2mbps; - uint32 rx5mbps5; - uint32 rx6mbps; - uint32 rx9mbps; - uint32 rx11mbps; - uint32 rx12mbps; - uint32 rx18mbps; - uint32 rx24mbps; - uint32 rx36mbps; - uint32 rx48mbps; - uint32 rx54mbps; - uint32 rx108mbps; - uint32 rx162mbps; - uint32 rx216mbps; - uint32 rx270mbps; - uint32 rx324mbps; - uint32 rx378mbps; - uint32 rx432mbps; - uint32 rx486mbps; - uint32 rx540mbps; -} wl_delta_stats_t; - -#define WL_WME_CNT_VERSION 1 +#define WL_WME_CNT_VERSION 1 typedef struct { uint32 packets; @@ -1235,28 +1705,35 @@ typedef struct { } wl_traffic_stats_t; typedef struct { - uint16 version; - uint16 length; + uint16 version; + uint16 length; - wl_traffic_stats_t tx[AC_COUNT]; - wl_traffic_stats_t tx_failed[AC_COUNT]; - wl_traffic_stats_t rx[AC_COUNT]; - wl_traffic_stats_t rx_failed[AC_COUNT]; + wl_traffic_stats_t tx[AC_COUNT]; + wl_traffic_stats_t tx_failed[AC_COUNT]; + wl_traffic_stats_t rx[AC_COUNT]; + wl_traffic_stats_t rx_failed[AC_COUNT]; - wl_traffic_stats_t forward[AC_COUNT]; + wl_traffic_stats_t forward[AC_COUNT]; - wl_traffic_stats_t tx_expired[AC_COUNT]; + wl_traffic_stats_t tx_expired[AC_COUNT]; } wl_wme_cnt_t; +struct wl_msglevel2 { + uint32 low; + uint32 high; +}; + + +#define WLC_ROAM_TRIGGER_DEFAULT 0 +#define WLC_ROAM_TRIGGER_BANDWIDTH 1 +#define WLC_ROAM_TRIGGER_DISTANCE 2 +#define WLC_ROAM_TRIGGER_AUTO 3 +#define WLC_ROAM_TRIGGER_MAX_VALUE 3 -#define WLC_ROAM_TRIGGER_DEFAULT 0 -#define WLC_ROAM_TRIGGER_BANDWIDTH 1 -#define WLC_ROAM_TRIGGER_DISTANCE 2 -#define WLC_ROAM_TRIGGER_AUTO 3 -#define WLC_ROAM_TRIGGER_MAX_VALUE 3 +#define WPA_AUTH_PFN_ANY 0xffffffff enum { PFN_LIST_ORDER, @@ -1268,50 +1745,113 @@ enum { ENABLE }; +enum { + OFF_ADAPT, + SMART_ADAPT, + STRICT_ADAPT +}; + #define SORT_CRITERIA_BIT 0 #define AUTO_NET_SWITCH_BIT 1 #define ENABLE_BKGRD_SCAN_BIT 2 #define IMMEDIATE_SCAN_BIT 3 #define AUTO_CONNECT_BIT 4 +#define ENABLE_BD_SCAN_BIT 5 +#define ENABLE_ADAPTSCAN_BIT 6 #define SORT_CRITERIA_MASK 0x01 #define AUTO_NET_SWITCH_MASK 0x02 #define ENABLE_BKGRD_SCAN_MASK 0x04 #define IMMEDIATE_SCAN_MASK 0x08 #define AUTO_CONNECT_MASK 0x10 +#define ENABLE_BD_SCAN_MASK 0x20 +#define ENABLE_ADAPTSCAN_MASK 0xc0 + +#define PFN_VERSION 2 +#define PFN_SCANRESULT_VERSION 1 +#define MAX_PFN_LIST_COUNT 16 + +#define PFN_COMPLETE 1 +#define PFN_INCOMPLETE 0 + +#define DEFAULT_BESTN 2 +#define DEFAULT_MSCAN 0 +#define DEFAULT_REPEAT 10 +#define DEFAULT_EXP 2 + -#define PFN_VERSION 1 +typedef struct wl_pfn_subnet_info { + struct ether_addr BSSID; + uint8 channel; + uint8 SSID_len; + uint8 SSID[32]; +} wl_pfn_subnet_info_t; + +typedef struct wl_pfn_net_info { + wl_pfn_subnet_info_t pfnsubnet; + int16 RSSI; + uint16 timestamp; +} wl_pfn_net_info_t; + +typedef struct wl_pfn_scanresults { + uint32 version; + uint32 status; + uint32 count; + wl_pfn_net_info_t netinfo[1]; +} wl_pfn_scanresults_t; typedef struct wl_pfn_param { - int32 version; - int32 scan_freq; + int32 version; + int32 scan_freq; int32 lost_network_timeout; int16 flags; int16 rssi_margin; + uint8 bestn; + uint8 mscan; + uint8 repeat; + uint8 exp; } wl_pfn_param_t; +typedef struct wl_pfn_bssid { + struct ether_addr macaddr; + + uint16 flags; +} wl_pfn_bssid_t; +#define WL_PFN_SUPPRESSFOUND_MASK 0x08 +#define WL_PFN_SUPPRESSLOST_MASK 0x10 + +typedef struct wl_pfn_cfg { + uint32 reporttype; + int32 channel_num; + uint16 channel_list[WL_NUMCHANNELS]; +} wl_pfn_cfg_t; +#define WL_PFN_REPORT_ALLNET 0 +#define WL_PFN_REPORT_SSIDNET 1 +#define WL_PFN_REPORT_BSSIDNET 2 + typedef struct wl_pfn { wlc_ssid_t ssid; - int32 bss_type; + int32 flags; int32 infra; int32 auth; int32 wpa_auth; int32 wsec; - union { - wl_wsec_key_t sec_key; - wsec_pmk_t wpa_sec_key; - } pfn_security; } wl_pfn_t; +#define WL_PFN_HIDDEN_BIT 2 +#define PNO_SCAN_MAX_FW 508*1000 +#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 +#define PNO_SCAN_MIN_FW_SEC 10 +#define WL_PFN_HIDDEN_MASK 0x4 -#define TOE_TX_CSUM_OL 0x00000001 -#define TOE_RX_CSUM_OL 0x00000002 +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 -#define TOE_ERRTEST_TX_CSUM 0x00000001 -#define TOE_ERRTEST_RX_CSUM 0x00000002 -#define TOE_ERRTEST_RX_CSUM2 0x00000004 +#define TOE_ERRTEST_TX_CSUM 0x00000001 +#define TOE_ERRTEST_RX_CSUM 0x00000002 +#define TOE_ERRTEST_RX_CSUM2 0x00000004 struct toe_ol_stats_t { @@ -1345,313 +1885,786 @@ struct toe_ol_stats_t { }; -#define ARP_OL_AGENT 0x00000001 -#define ARP_OL_SNOOP 0x00000002 -#define ARP_OL_HOST_AUTO_REPLY 0x00000004 -#define ARP_OL_PEER_AUTO_REPLY 0x00000008 +#define ARP_OL_AGENT 0x00000001 +#define ARP_OL_SNOOP 0x00000002 +#define ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define ARP_OL_PEER_AUTO_REPLY 0x00000008 -#define ARP_ERRTEST_REPLY_PEER 0x1 -#define ARP_ERRTEST_REPLY_HOST 0x2 +#define ARP_ERRTEST_REPLY_PEER 0x1 +#define ARP_ERRTEST_REPLY_HOST 0x2 -#define ARP_MULTIHOMING_MAX 8 +#define ARP_MULTIHOMING_MAX 8 struct arp_ol_stats_t { - uint32 host_ip_entries; - uint32 host_ip_overflow; + uint32 host_ip_entries; + uint32 host_ip_overflow; - uint32 arp_table_entries; - uint32 arp_table_overflow; + uint32 arp_table_entries; + uint32 arp_table_overflow; - uint32 host_request; - uint32 host_reply; - uint32 host_service; + uint32 host_request; + uint32 host_reply; + uint32 host_service; - uint32 peer_request; - uint32 peer_request_drop; - uint32 peer_reply; - uint32 peer_reply_drop; - uint32 peer_service; + uint32 peer_request; + uint32 peer_request_drop; + uint32 peer_reply; + uint32 peer_reply_drop; + uint32 peer_service; }; +typedef struct wl_keep_alive_pkt { + uint32 period_msec; + uint16 len_bytes; + uint8 data[1]; +} wl_keep_alive_pkt_t; +#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) -typedef struct wl_keep_alive_pkt { - - uint32 period_msec; - - uint16 len_bytes; - - uint8 data[1]; +typedef enum wl_pkt_filter_type { + WL_PKT_FILTER_TYPE_PATTERN_MATCH +} wl_pkt_filter_type_t; -} wl_keep_alive_pkt_t; +#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t -#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) +typedef struct wl_pkt_filter_pattern { + uint32 offset; + uint32 size_bytes; + uint8 mask_and_pattern[1]; +} wl_pkt_filter_pattern_t; +typedef struct wl_pkt_filter { + uint32 id; + uint32 type; + uint32 negate_match; + union { + wl_pkt_filter_pattern_t pattern; + } u; +} wl_pkt_filter_t; +#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) +#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) -typedef enum WL_PKT_FILTER_TYPE { - - WL_PKT_FILTER_TYPE_PATTERN_MATCH +typedef struct wl_pkt_filter_enable { + uint32 id; + uint32 enable; +} wl_pkt_filter_enable_t; - -} WL_PKT_FILTER_TYPE; +typedef struct wl_pkt_filter_list { + uint32 num; + wl_pkt_filter_t filter[1]; +} wl_pkt_filter_list_t; +#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) -typedef struct wl_pkt_filter_pattern { - - uint32 offset; +typedef struct wl_pkt_filter_stats { + uint32 num_pkts_matched; + uint32 num_pkts_forwarded; + uint32 num_pkts_discarded; +} wl_pkt_filter_stats_t; - - uint32 size_bytes; - - uint8 mask_and_pattern[1]; +typedef struct wl_seq_cmd_ioctl { + uint32 cmd; + uint32 len; +} wl_seq_cmd_ioctl_t; -} wl_pkt_filter_pattern_t; +#define WL_SEQ_CMD_ALIGN_BYTES 4 +#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ + (((cmd) == WLC_GET_MAGIC) || \ + ((cmd) == WLC_GET_VERSION) || \ + ((cmd) == WLC_GET_AP) || \ + ((cmd) == WLC_GET_INSTANCE)) -typedef struct wl_pkt_filter { - - uint32 id; - - uint32 type; - - uint32 negate_match; +#define WL_PKTENG_PER_TX_START 0x01 +#define WL_PKTENG_PER_TX_STOP 0x02 +#define WL_PKTENG_PER_RX_START 0x04 +#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 +#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 +#define WL_PKTENG_PER_RX_STOP 0x08 +#define WL_PKTENG_PER_MASK 0xff - - union - { - - wl_pkt_filter_pattern_t pattern; +#define WL_PKTENG_SYNCHRONOUS 0x100 - - - } u; +typedef struct wl_pkteng { + uint32 flags; + uint32 delay; + uint32 nframes; + uint32 length; + uint8 seqno; + struct ether_addr dest; + struct ether_addr src; +} wl_pkteng_t; +#define NUM_80211b_RATES 4 +#define NUM_80211ag_RATES 8 +#define NUM_80211n_RATES 32 +#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) +typedef struct wl_pkteng_stats { + uint32 lostfrmcnt; + int32 rssi; + int32 snr; + uint16 rxpktcnt[NUM_80211_RATES+1]; +} wl_pkteng_stats_t; + + +#define WL_WOWL_MAGIC (1 << 0) +#define WL_WOWL_NET (1 << 1) +#define WL_WOWL_DIS (1 << 2) +#define WL_WOWL_RETR (1 << 3) +#define WL_WOWL_BCN (1 << 4) +#define WL_WOWL_TST (1 << 5) +#define WL_WOWL_M1 (1 << 6) +#define WL_WOWL_EAPID (1 << 7) +#define WL_WOWL_KEYROT (1 << 14) +#define WL_WOWL_BCAST (1 << 15) + +#define MAGIC_PKT_MINLEN 102 + +typedef struct { + uint masksize; + uint offset; + uint patternoffset; + uint patternsize; + ulong id; + +} wl_wowl_pattern_t; -} wl_pkt_filter_t; +typedef struct { + uint count; + wl_wowl_pattern_t pattern[1]; +} wl_wowl_pattern_list_t; +typedef struct { + uint8 pci_wakeind; + uint16 ucode_wakeind; +} wl_wowl_wakeind_t; -#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) -#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) +typedef struct wl_txrate_class { + uint8 init_rate; + uint8 min_rate; + uint8 max_rate; +} wl_txrate_class_t; -typedef struct wl_pkt_filter_enable { - - uint32 id; - - uint32 enable; +#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 +#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 +#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 +#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 +#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 +#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 +#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 +#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 +#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 -} wl_pkt_filter_enable_t; +typedef struct wl_obss_scan_arg { + int16 passive_dwell; + int16 active_dwell; + int16 bss_widthscan_interval; + int16 passive_total; + int16 active_total; + int16 chanwidth_transition_delay; + int16 activity_threshold; +} wl_obss_scan_arg_t; + +#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) +#define WL_MIN_NUM_OBSS_SCAN_ARG 7 +#define WL_COEX_INFO_MASK 0x07 +#define WL_COEX_INFO_REQ 0x01 +#define WL_COEX_40MHZ_INTOLERANT 0x02 +#define WL_COEX_WIDTH20 0x04 -typedef struct wl_pkt_filter_list { +#define WLC_RSSI_INVALID 0 + +#define MAX_RSSI_LEVELS 8 - - uint32 num; +typedef struct wl_rssi_event { + uint32 rate_limit_msec; + uint8 num_rssi_levels; + int8 rssi_levels[MAX_RSSI_LEVELS]; +} wl_rssi_event_t; + +typedef struct wl_action_obss_coex_req { + uint8 info; + uint8 num; + uint8 ch_list[1]; +} wl_action_obss_coex_req_t; + + +#define EXTLOG_CUR_VER 0x0100 + +#define MAX_ARGSTR_LEN 18 + + +#define LOG_MODULE_COMMON 0x0001 +#define LOG_MODULE_ASSOC 0x0002 +#define LOG_MODULE_EVENT 0x0004 +#define LOG_MODULE_MAX 3 + + +#define WL_LOG_LEVEL_DISABLE 0 +#define WL_LOG_LEVEL_ERR 1 +#define WL_LOG_LEVEL_WARN 2 +#define WL_LOG_LEVEL_INFO 3 +#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO + + +#define LOG_FLAG_EVENT 1 + + +#define LOG_ARGTYPE_NULL 0 +#define LOG_ARGTYPE_STR 1 +#define LOG_ARGTYPE_INT 2 +#define LOG_ARGTYPE_INT_STR 3 +#define LOG_ARGTYPE_STR_INT 4 + +typedef struct wlc_extlog_cfg { + int max_number; + uint16 module; + uint8 level; + uint8 flag; + uint16 version; +} wlc_extlog_cfg_t; + +typedef struct log_record { + uint32 time; + uint16 module; + uint16 id; + uint8 level; + uint8 sub_unit; + uint8 seq_num; + int32 arg; + char str[MAX_ARGSTR_LEN]; +} log_record_t; + +typedef struct wlc_extlog_req { + uint32 from_last; + uint32 num; +} wlc_extlog_req_t; + +typedef struct wlc_extlog_results { + uint16 version; + uint16 record_len; + uint32 num; + log_record_t logs[1]; +} wlc_extlog_results_t; + +typedef struct log_idstr { + uint16 id; + uint16 flag; + uint8 arg_type; + const char *fmt_str; +} log_idstr_t; + +#define FMTSTRF_USER 1 + + +typedef enum { + FMTSTR_DRIVER_UP_ID = 0, + FMTSTR_DRIVER_DOWN_ID = 1, + FMTSTR_SUSPEND_MAC_FAIL_ID = 2, + FMTSTR_NO_PROGRESS_ID = 3, + FMTSTR_RFDISABLE_ID = 4, + FMTSTR_REG_PRINT_ID = 5, + FMTSTR_EXPTIME_ID = 6, + FMTSTR_JOIN_START_ID = 7, + FMTSTR_JOIN_COMPLETE_ID = 8, + FMTSTR_NO_NETWORKS_ID = 9, + FMTSTR_SECURITY_MISMATCH_ID = 10, + FMTSTR_RATE_MISMATCH_ID = 11, + FMTSTR_AP_PRUNED_ID = 12, + FMTSTR_KEY_INSERTED_ID = 13, + FMTSTR_DEAUTH_ID = 14, + FMTSTR_DISASSOC_ID = 15, + FMTSTR_LINK_UP_ID = 16, + FMTSTR_LINK_DOWN_ID = 17, + FMTSTR_RADIO_HW_OFF_ID = 18, + FMTSTR_RADIO_HW_ON_ID = 19, + FMTSTR_EVENT_DESC_ID = 20, + FMTSTR_PNP_SET_POWER_ID = 21, + FMTSTR_RADIO_SW_OFF_ID = 22, + FMTSTR_RADIO_SW_ON_ID = 23, + FMTSTR_PWD_MISMATCH_ID = 24, + FMTSTR_FATAL_ERROR_ID = 25, + FMTSTR_AUTH_FAIL_ID = 26, + FMTSTR_ASSOC_FAIL_ID = 27, + FMTSTR_IBSS_FAIL_ID = 28, + FMTSTR_EXTAP_FAIL_ID = 29, + FMTSTR_MAX_ID +} log_fmtstr_id_t; + +#ifdef DONGLEOVERLAYS +typedef struct { + uint32 flags_idx; + uint32 offset; + uint32 len; - wl_pkt_filter_t filter[1]; +} wl_ioctl_overlay_t; -} wl_pkt_filter_list_t; +#define OVERLAY_IDX_MASK 0x000000ff +#define OVERLAY_IDX_SHIFT 0 +#define OVERLAY_FLAGS_MASK 0xffffff00 +#define OVERLAY_FLAGS_SHIFT 8 +#define OVERLAY_FLAG_POSTLOAD 0x100 -#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) +#define OVERLAY_FLAG_DEFER_DL 0x200 +#define OVERLAY_FLAG_PRESLEEP 0x400 +#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 +#endif -typedef struct wl_pkt_filter_stats { - - uint32 num_pkts_matched; +#include <packed_section_end.h> - - uint32 num_pkts_forwarded; - - uint32 num_pkts_discarded; +#include <packed_section_start.h> -} wl_pkt_filter_stats_t; +#define VNDR_IE_CMD_LEN 4 +#define VNDR_IE_BEACON_FLAG 0x1 +#define VNDR_IE_PRBRSP_FLAG 0x2 +#define VNDR_IE_ASSOCRSP_FLAG 0x4 +#define VNDR_IE_AUTHRSP_FLAG 0x8 +#define VNDR_IE_PRBREQ_FLAG 0x10 +#define VNDR_IE_ASSOCREQ_FLAG 0x20 +#define VNDR_IE_CUSTOM_FLAG 0x100 +#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) -typedef struct wl_seq_cmd_ioctl { - uint32 cmd; - uint32 len; -} wl_seq_cmd_ioctl_t; +typedef BWL_PRE_PACKED_STRUCT struct { + uint32 pktflag; + vndr_ie_t vndr_ie_data; +} BWL_POST_PACKED_STRUCT vndr_ie_info_t; -#define WL_SEQ_CMD_ALIGN_BYTES 4 +typedef BWL_PRE_PACKED_STRUCT struct { + int iecount; + vndr_ie_info_t vndr_ie_list[1]; +} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; +typedef BWL_PRE_PACKED_STRUCT struct { + char cmd[VNDR_IE_CMD_LEN]; + vndr_ie_buf_t vndr_ie_buffer; +} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; -#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ - (((cmd) == WLC_GET_MAGIC) || \ - ((cmd) == WLC_GET_VERSION) || \ - ((cmd) == WLC_GET_AP) || \ - ((cmd) == WLC_GET_INSTANCE)) +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; -#define WL_PKTENG_PER_TX_START 0x01 -#define WL_PKTENG_PER_TX_STOP 0x02 -#define WL_PKTENG_PER_RX_START 0x04 -#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 -#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 -#define WL_PKTENG_PER_RX_STOP 0x08 -#define WL_PKTENG_PER_MASK 0xff +#ifdef WLMEDIA_TXFAILEVENT +typedef BWL_PRE_PACKED_STRUCT struct { + char dest[ETHER_ADDR_LEN]; + uint8 prio; + uint8 flags; + uint32 tsf_l; + uint32 tsf_h; + uint16 rates; + uint16 txstatus; +} BWL_POST_PACKED_STRUCT txfailinfo_t; +#endif -#define WL_PKTENG_SYNCHRONOUS 0x100 +#include <packed_section_end.h> -typedef struct wl_pkteng { - uint32 flags; - uint32 delay; - uint32 nframes; - uint32 length; - uint8 seqno; - struct ether_addr dest; - struct ether_addr src; -} wl_pkteng_t; -typedef struct wl_pkteng_stats { - uint32 lostfrmcnt; - int32 rssi; - int32 snr; -} wl_pkteng_stats_t; +#define ASSERTLOG_CUR_VER 0x0100 +#define MAX_ASSRTSTR_LEN 64 -#define WL_WOWL_MAGIC (1 << 0) -#define WL_WOWL_NET (1 << 1) -#define WL_WOWL_DIS (1 << 2) -#define WL_WOWL_RETR (1 << 3) -#define WL_WOWL_BCN (1 << 4) -#define WL_WOWL_TST (1 << 5) -#define WL_WOWL_BCAST (1 << 15) +typedef struct assert_record { + uint32 time; + uint8 seq_num; + char str[MAX_ASSRTSTR_LEN]; +} assert_record_t; -#define MAGIC_PKT_MINLEN 102 +typedef struct assertlog_results { + uint16 version; + uint16 record_len; + uint32 num; + assert_record_t logs[1]; +} assertlog_results_t; + +#define LOGRRC_FIX_LEN 8 +#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) + + + + + +#define CHANIM_DISABLE 0 +#define CHANIM_DETECT 1 +#define CHANIM_ACT 2 +#define CHANIM_MODE_MAX 2 + + +#define APCS_IOCTL 1 +#define APCS_CHANIM 2 +#define APCS_CSTIMER 3 +#define APCS_BTA 4 + + +#define CHANIM_ACS_RECORD 10 -typedef struct { - uint masksize; - uint offset; - uint patternoffset; - uint patternsize; - - -} wl_wowl_pattern_t; typedef struct { - uint count; - wl_wowl_pattern_t pattern[1]; -} wl_wowl_pattern_list_t; + bool valid; + uint8 trigger; + chanspec_t selected_chspc; + uint32 glitch_cnt; + uint8 ccastats; + uint timestamp; +} chanim_acs_record_t; typedef struct { - uint8 pci_wakeind; - uint16 ucode_wakeind; -} wl_wowl_wakeind_t; + chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; + uint8 count; + uint timestamp; +} wl_acs_record_t; -typedef struct wl_txrate_class { - uint8 init_rate; - uint8 min_rate; - uint8 max_rate; -} wl_txrate_class_t; +#define SMFS_VERSION 1 +typedef struct wl_smfs_elem { + uint32 count; + uint16 code; +} wl_smfs_elem_t; +typedef struct wl_smf_stats { + uint32 version; + uint16 length; + uint8 type; + uint8 codetype; + uint32 ignored_cnt; + uint32 malformed_cnt; + uint32 count_total; + wl_smfs_elem_t elem[1]; +} wl_smf_stats_t; -#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 100 -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 -#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 -#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 20 -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 -#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 -#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 -#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 -#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 -#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 -#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 +#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); +enum { + SMFS_CODETYPE_SC, + SMFS_CODETYPE_RC +}; -typedef struct wl_obss_scan_arg { - int16 passive_dwell; - int16 active_dwell; - int16 bss_widthscan_interval; - int16 passive_total; - int16 active_total; - int16 chanwidth_transition_delay; - int16 activity_threshold; -} wl_obss_scan_arg_t; -#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) -#define WL_MIN_NUM_OBSS_SCAN_ARG 7 -#define WL_COEX_INFO_MASK 0x07 -#define WL_COEX_INFO_REQ 0x01 -#define WL_COEX_40MHZ_INTOLERANT 0x02 -#define WL_COEX_WIDTH20 0x04 +#define SMFS_CODE_MALFORMED 0xFFFE +#define SMFS_CODE_IGNORED 0xFFFD +typedef enum smfs_type { + SMFS_TYPE_AUTH, + SMFS_TYPE_ASSOC, + SMFS_TYPE_REASSOC, + SMFS_TYPE_DISASSOC_TX, + SMFS_TYPE_DISASSOC_RX, + SMFS_TYPE_DEAUTH_TX, + SMFS_TYPE_DEAUTH_RX, + SMFS_TYPE_MAX +} smfs_type_t; -#define MAX_RSSI_LEVELS 8 +#ifdef PHYMON +#define PHYMON_VERSION 1 -typedef struct wl_rssi_event { +typedef struct wl_phycal_core_state { - uint32 rate_limit_msec; + int16 tx_iqlocal_a; + int16 tx_iqlocal_b; + int8 tx_iqlocal_ci; + int8 tx_iqlocal_cq; + int8 tx_iqlocal_di; + int8 tx_iqlocal_dq; + int8 tx_iqlocal_ei; + int8 tx_iqlocal_eq; + int8 tx_iqlocal_fi; + int8 tx_iqlocal_fq; + - uint8 num_rssi_levels; + int16 rx_iqcal_a; + int16 rx_iqcal_b; + + uint8 tx_iqlocal_pwridx; + uint32 papd_epsilon_table[64]; + int16 papd_epsilon_offset; + uint8 curr_tx_pwrindex; + int8 idle_tssi; + int8 est_tx_pwr; + int8 est_rx_pwr; + uint16 rx_gaininfo; + uint16 init_gaincode; + int8 estirr_tx; + int8 estirr_rx; + +} wl_phycal_core_state_t; + +typedef struct wl_phycal_state { + int version; + int8 num_phy_cores; + int8 curr_temperature; + chanspec_t chspec; + bool aci_state; + uint16 crsminpower; + uint16 crsminpowerl; + uint16 crsminpoweru; + wl_phycal_core_state_t phycal_core[1]; +} wl_phycal_state_t; + +#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) +#endif + +#ifdef WLP2P + +typedef struct wl_p2p_disc_st { + uint8 state; + chanspec_t chspec; + uint16 dwell; +} wl_p2p_disc_st_t; + + +#define WL_P2P_DISC_ST_SCAN 0 +#define WL_P2P_DISC_ST_LISTEN 1 +#define WL_P2P_DISC_ST_SEARCH 2 + + +typedef struct wl_p2p_scan { + uint8 type; + uint8 reserved[3]; - int8 rssi_levels[MAX_RSSI_LEVELS]; -} wl_rssi_event_t; +} wl_p2p_scan_t; + + +typedef struct wl_p2p_if { + struct ether_addr addr; + uint8 type; + chanspec_t chspec; +} wl_p2p_if_t; + + +#define WL_P2P_IF_CLIENT 0 +#define WL_P2P_IF_GO 1 +#define WL_P2P_IF_DYNBCN_GO 2 +#define WL_P2P_IF_DEV 3 + + +typedef struct wl_p2p_ifq { + uint bsscfgidx; + char ifname[BCM_MSG_IFNAME_MAX]; +} wl_p2p_ifq_t; + + +typedef struct wl_p2p_ops { + uint8 ops; + uint8 ctw; +} wl_p2p_ops_t; + + +typedef struct wl_p2p_sched_desc { + uint32 start; + uint32 interval; + uint32 duration; + uint32 count; +} wl_p2p_sched_desc_t; + + +#define WL_P2P_SCHED_RSVD 0 +#define WL_P2P_SCHED_REPEAT 255 + +typedef struct wl_p2p_sched { + uint8 type; + uint8 action; + uint8 option; + wl_p2p_sched_desc_t desc[1]; +} wl_p2p_sched_t; +#define WL_P2P_SCHED_FIXED_LEN 3 + + +#define WL_P2P_SCHED_TYPE_ABS 0 +#define WL_P2P_SCHED_TYPE_REQ_ABS 1 + + +#define WL_P2P_SCHED_ACTION_NONE 0 +#define WL_P2P_SCHED_ACTION_DOZE 1 + +#define WL_P2P_SCHED_ACTION_GOOFF 2 + +#define WL_P2P_SCHED_ACTION_RESET 255 + + +#define WL_P2P_SCHED_OPTION_NORMAL 0 +#define WL_P2P_SCHED_OPTION_BCNPCT 1 + +#define WL_P2P_SCHED_OPTION_TSFOFS 2 + + +#define WL_P2P_FEAT_GO_CSA (1 << 0) +#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) +#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) +#endif + + +#define BCM_ACTION_RFAWARE 0x77 +#define BCM_ACTION_RFAWARE_DCS 0x01 + + + +#define WL_11N_2x2 1 +#define WL_11N_3x3 3 +#define WL_11N_4x4 4 + + +#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 + + +#define LQ_IDX_LAST 3 +#define MCS_INDEX_SIZE 33 + +#define LQ_IDX_MIN 0 +#define LQ_IDX_MAX 1 +#define LQ_IDX_AVG 2 +#define LQ_IDX_SUM 2 +#define LQ_IDX_LAST 3 +#define LQ_STOP_MONITOR 0 +#define LQ_START_MONITOR 1 + +#define LINKQUAL_V1 0x01 + +struct wl_lq { + int32 enable; + int32 rssi[LQ_IDX_LAST]; + int32 rssicnt; + int32 snr[LQ_IDX_LAST]; + uint32 nsamples; + uint8 isvalid; + uint8 version; +}; + +typedef struct wl_lq wl_lq_t; +typedef struct wl_lq wl_lq_stats_t; + +typedef struct { + struct ether_addr ea; + uint8 ac_cat; + uint8 num_pkts; +} wl_mac_ratehisto_cmd_t; typedef struct { - ComplexShort Vpapd; - ComplexShort Vpapd_openTR; - int16 Pdelta_fwd; - int16 Pdelta_fbk; - int16 Pdelta_fwd_qQ; - int16 Pdelta_fbk_qQ; - int16 calc_vswr_correction; - int16 applied_vswr_correction; - uint8 vswr_cal_en; - uint8 vswr_corr_en; - uint8 vswr_corr_max; - int16 vswr_corr_bias; -} lpphy_vswr_cal_t; + uint32 rate[WLC_MAXRATE + 1]; + uint32 mcs_index[MCS_INDEX_SIZE]; + uint32 tsf_timer[2][2]; +} wl_mac_ratehisto_res_t; +#ifdef PROP_TXSTATUS -#include <packed_section_end.h> +#define WLFC_FLAGS_RSSI_SIGNALS 1 + + +#define WLFC_FLAGS_XONXOFF_SIGNALS 2 + + +#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 4 + +#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 8 +#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 16 +#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 32 +#endif + +#define BTA_STATE_LOG_SZ 64 + + +enum { + HCIReset = 1, + HCIReadLocalAMPInfo, + HCIReadLocalAMPASSOC, + HCIWriteRemoteAMPASSOC, + HCICreatePhysicalLink, + HCIAcceptPhysicalLinkRequest, + HCIDisconnectPhysicalLink, + HCICreateLogicalLink, + HCIAcceptLogicalLink, + HCIDisconnectLogicalLink, + HCILogicalLinkCancel, + HCIAmpStateChange, + HCIWriteLogicalLinkAcceptTimeout +}; + +typedef struct flush_txfifo { + uint32 txfifobmp; + uint32 hwtxfifoflush; + struct ether_addr ea; +} flush_txfifo_t; + +#define CHANNEL_5G_LOW_START 36 +#define CHANNEL_5G_MID_START 52 +#define CHANNEL_5G_HIGH_START 100 +#define CHANNEL_5G_UPPER_START 149 + +enum { + SPATIAL_MODE_2G_IDX = 0, + SPATIAL_MODE_5G_LOW_IDX, + SPATIAL_MODE_5G_MID_IDX, + SPATIAL_MODE_5G_HIGH_IDX, + SPATIAL_MODE_5G_UPPER_IDX, + SPATIAL_MODE_MAX_IDX +}; #endif diff --git a/src/shared/aiutils.c b/src/shared/aiutils.c index bd3f8aa..059df89 100644 --- a/src/shared/aiutils.c +++ b/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-2011, 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,9 +22,10 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aiutils.c,v 1.6.4.7 2008/08/06 03:43:25 Exp $ + * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $ */ + #include <typedefs.h> #include <bcmdefs.h> #include <osl.h> @@ -36,17 +37,19 @@ #include "siutils_priv.h" -/* EROM parsing */ + + + static uint32 -get_erom_ent(si_t *sih, uint32 *eromptr, uint32 mask, uint32 match) +get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) { uint32 ent; uint inv = 0, nom = 0; while (TRUE) { - ent = R_REG(si_osh(sih), (uint32 *)(uintptr)(*eromptr)); - *eromptr += sizeof(uint32); + ent = R_REG(si_osh(sih), *eromptr); + (*eromptr)++; if (mask == 0) break; @@ -65,14 +68,15 @@ get_erom_ent(si_t *sih, uint32 *eromptr, uint32 mask, uint32 match) nom++; } - SI_MSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); - if (inv + nom) - SI_MSG((" after %d invalid and %d non-matching entries\n", inv, nom)); + SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); + if (inv + nom) { + SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); + } return ent; } static uint32 -get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, +get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, uint32 *sizel, uint32 *sizeh) { uint32 asd, sz, szd; @@ -81,8 +85,8 @@ get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st, uint32 *addrl, ui if (((asd & ER_TAG1) != ER_ADD) || (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ((asd & AD_ST_MASK) != st)) { - /* This is not what we want, "push" it back */ - *eromptr -= sizeof(uint32); + + (*eromptr)--; return 0; } *addrl = asd & AD_ADDR_MASK; @@ -100,39 +104,44 @@ get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st, uint32 *addrl, ui } else *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); - SI_MSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", + SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); return asd; } -/* parse the enumeration rom to identify all cores */ +static void +ai_hwfixup(si_info_t *sii) +{ +} + + void ai_scan(si_t *sih, void *regs, uint devid) { si_info_t *sii = SI_INFO(sih); chipcregs_t *cc = (chipcregs_t *)regs; - uint32 erombase, eromptr, eromlim; + uint32 erombase, *eromptr, *eromlim; erombase = R_REG(sii->osh, &cc->eromptr); switch (BUSTYPE(sih->bustype)) { case SI_BUS: - eromptr = (uintptr)REG_MAP(erombase, SI_CORE_SIZE); + eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); break; case PCI_BUS: - /* Set wrappers address */ + sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); - /* Now point the window at the erom */ + OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); - eromptr = (uint32)(uintptr)regs; + eromptr = regs; break; case SPI_BUS: case SDIO_BUS: - eromptr = erombase; + eromptr = (uint32 *)(uintptr)erombase; break; case PCMCIA_BUS: @@ -141,25 +150,27 @@ ai_scan(si_t *sih, void *regs, uint devid) ASSERT(0); return; } - eromlim = eromptr + ER_REMAPCONTROL; + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - SI_MSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%08x, eromlim = 0x%08x\n", - regs, erombase, eromptr, eromlim)); + SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", + regs, erombase, eromptr, eromlim)); while (eromptr < eromlim) { - uint32 cia, cib, base, cid, mfg, crev, nmw, nsw, nmp, nsp; + uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; uint32 mpd, asd, addrl, addrh, sizel, sizeh; + uint32 *base; uint i, j, idx; bool br; br = FALSE; - /* Grok a component */ + cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); if (cia == (ER_END | ER_VALID)) { - SI_MSG(("Found END of erom after %d cores\n", sii->numcores)); + SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); + ai_hwfixup(sii); return; } - base = eromptr - sizeof(uint32); + base = eromptr - 1; cib = get_erom_ent(sih, &eromptr, 0, 0); if ((cib & ER_TAG) != ER_CI) { @@ -175,29 +186,29 @@ ai_scan(si_t *sih, void *regs, uint devid) nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - SI_MSG(("Found component 0x%04x/0x%4x rev %d at erom addr 0x%08x, with nmw = %d, " - "nsw = %d, nmp = %d & nsp = %d\n", - mfg, cid, crev, base, nmw, nsw, nmp, nsp)); + SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " + "nsw = %d, nmp = %d & nsp = %d\n", + mfg, cid, crev, base, nmw, nsw, nmp, nsp)); if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) continue; if ((nmw + nsw == 0)) { - /* A component which is not a core */ + if (cid == OOB_ROUTER_CORE_ID) { asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if (asd != 0) { - sii->common_info->oob_router = addrl; + sii->oob_router = addrl; } } continue; } idx = sii->numcores; -/* sii->eromptr[idx] = base; */ - sii->common_info->cia[idx] = cia; - sii->common_info->cib[idx] = cib; - sii->common_info->coreid[idx] = cid; + + sii->cia[idx] = cia; + sii->cib[idx] = cib; + sii->coreid[idx] = cid; for (i = 0; i < nmp; i++) { mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); @@ -205,17 +216,15 @@ ai_scan(si_t *sih, void *regs, uint devid) SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); goto error; } - SI_MSG((" Master port %d, mp: %d id: %d\n", i, - (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, - (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); + SI_VMSG((" Master port %d, mp: %d id: %d\n", i, + (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, + (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); } - /* First Slave Address Descriptor should be port 0: - * the main register space for the core - */ + asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); if (asd == 0) { - /* Try again to see if it is a bridge */ + asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, &sizel, &sizeh); if (asd != 0) @@ -227,20 +236,21 @@ ai_scan(si_t *sih, void *regs, uint devid) goto error; } } - sii->common_info->coresba[idx] = addrl; - sii->common_info->coresba_size[idx] = sizel; - /* Get any more ASDs in port 0 */ + sii->coresba[idx] = addrl; + sii->coresba_size[idx] = sizel; + j = 1; do { asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); - if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) - sii->common_info->coresba2[idx] = addrl; - sii->common_info->coresba2_size[idx] = sizel; + if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { + sii->coresba2[idx] = addrl; + sii->coresba2_size[idx] = sizel; + } j++; } while (asd != 0); - /* Go through the ASDs for other slave ports */ + for (i = 1; i < nsp; i++) { j = 0; do { @@ -253,7 +263,7 @@ ai_scan(si_t *sih, void *regs, uint devid) } } - /* Now get master wrappers */ + for (i = 0; i < nmw; i++) { asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, &sizel, &sizeh); @@ -266,10 +276,10 @@ ai_scan(si_t *sih, void *regs, uint devid) goto error; } if (i == 0) - sii->common_info->wrapba[idx] = addrl; + sii->wrapba[idx] = addrl; } - /* And finally slave wrappers */ + for (i = 0; i < nsw; i++) { uint fwp = (nsp == 1) ? 0 : 1; asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, @@ -283,14 +293,14 @@ ai_scan(si_t *sih, void *regs, uint devid) goto error; } if ((nmw == 0) && (i == 0)) - sii->common_info->wrapba[idx] = addrl; + sii->wrapba[idx] = addrl; } - /* Don't record bridges */ + if (br) continue; - /* Done with core */ + sii->numcores++; } @@ -301,39 +311,34 @@ error: return; } -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ + void * ai_setcoreidx(si_t *sih, uint coreidx) { si_info_t *sii = SI_INFO(sih); - uint32 addr = sii->common_info->coresba[coreidx]; - uint32 wrap = sii->common_info->wrapba[coreidx]; + uint32 addr = sii->coresba[coreidx]; + uint32 wrap = sii->wrapba[coreidx]; void *regs; if (coreidx >= sii->numcores) return (NULL); - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ + ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); switch (BUSTYPE(sih->bustype)) { case SI_BUS: - /* map new one */ - if (!sii->common_info->regs[coreidx]) { - sii->common_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->common_info->regs[coreidx])); + + if (!sii->regs[coreidx]) { + sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); + ASSERT(GOODREGS(sii->regs[coreidx])); } - sii->curmap = regs = sii->common_info->regs[coreidx]; - if (!sii->common_info->wrappers[coreidx]) { - sii->common_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->common_info->wrappers[coreidx])); + sii->curmap = regs = sii->regs[coreidx]; + if (!sii->wrappers[coreidx]) { + sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); + ASSERT(GOODREGS(sii->wrappers[coreidx])); } - sii->curwrap = sii->common_info->wrappers[coreidx]; + sii->curwrap = sii->wrappers[coreidx]; break; @@ -356,14 +361,14 @@ ai_setcoreidx(si_t *sih, uint coreidx) return regs; } -/* Return the number of address spaces in current core */ + int ai_numaddrspaces(si_t *sih) { return 2; } -/* Return the address of the nth address space in the current core */ + uint32 ai_addrspace(si_t *sih, uint asidx) { @@ -374,9 +379,9 @@ ai_addrspace(si_t *sih, uint asidx) cidx = sii->curidx; if (asidx == 0) - return sii->common_info->coresba[cidx]; + return sii->coresba[cidx]; else if (asidx == 1) - return sii->common_info->coresba2[cidx]; + return sii->coresba2[cidx]; else { SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __FUNCTION__, asidx)); @@ -384,7 +389,7 @@ ai_addrspace(si_t *sih, uint asidx) } } -/* Return the size of the nth address space in the current core */ + uint32 ai_addrspacesize(si_t *sih, uint asidx) { @@ -395,9 +400,9 @@ ai_addrspacesize(si_t *sih, uint asidx) cidx = sii->curidx; if (asidx == 0) - return sii->common_info->coresba_size[cidx]; + return sii->coresba_size[cidx]; else if (asidx == 1) - return sii->common_info->coresba2_size[cidx]; + return sii->coresba2_size[cidx]; else { SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __FUNCTION__, asidx)); @@ -423,13 +428,29 @@ ai_setint(si_t *sih, int siflag) } uint +ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + si_info_t *sii = SI_INFO(sih); + uint32 *map = (uint32 *) sii->curwrap; + + if (mask || val) { + uint32 w = R_REG(sii->osh, map+(offset/4)); + w &= ~mask; + w |= val; + W_REG(sii->osh, map+(offset/4), val); + } + + return (R_REG(sii->osh, map+(offset/4))); +} + +uint ai_corevendor(si_t *sih) { si_info_t *sii; uint32 cia; sii = SI_INFO(sih); - cia = sii->common_info->cia[sii->curidx]; + cia = sii->cia[sii->curidx]; return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); } @@ -440,7 +461,7 @@ ai_corerev(si_t *sih) uint32 cib; sii = SI_INFO(sih); - cib = sii->common_info->cib[sii->curidx]; + cib = sii->cib[sii->curidx]; return ((cib & CIB_REV_MASK) >> CIB_REV_SHIFT); } @@ -457,15 +478,7 @@ ai_iscoreup(si_t *sih) ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); } -/* - * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, - * switch back to the original core, and return the new value. - * - * When using the silicon backplane, no fidleing with interrupts or core switches are needed. - * - * Also, when using pci/pcie, we can optimize away the core switching for pci registers - * and (on newer pci cores) chipcommon registers. - */ + uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { @@ -482,28 +495,29 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ASSERT(regoff < SI_CORE_SIZE); ASSERT((val & ~mask) == 0); + if (coreidx >= SI_MAXCORES) + return 0; + if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ + fast = TRUE; - /* map if does not exist */ - if (!sii->common_info->wrappers[coreidx]) { - sii->common_info->regs[coreidx] = - REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE); - ASSERT(GOODREGS(sii->common_info->regs[coreidx])); + + if (!sii->regs[coreidx]) { + sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(sii->regs[coreidx])); } - r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff); + r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ + - if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ + if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + fast = TRUE; r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ + fast = TRUE; if (SI_FAST(sii)) r = (uint32 *)((char *)sii->curmap + @@ -519,25 +533,25 @@ ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) if (!fast) { INTR_OFF(sii, intr_val); - /* save current core index */ + origidx = si_coreidx(&sii->pub); - /* switch core */ + r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); } ASSERT(r != NULL); - /* mask and set */ + if (mask || val) { w = (R_REG(sii->osh, r) & ~mask) | val; W_REG(sii->osh, r, w); } - /* readback */ + w = R_REG(sii->osh, r); if (!fast) { - /* restore core index */ + if (origidx != coreidx) ai_setcoreidx(&sii->pub, origidx); @@ -559,7 +573,7 @@ ai_core_disable(si_t *sih, uint32 bits) ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; - /* if core is already in reset, just return */ + if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) return; @@ -571,11 +585,7 @@ ai_core_disable(si_t *sih, uint32 bits) OSL_DELAY(1); } -/* reset and re-enable a core - * inputs: - * bits - core specific bits that are set during and after reset sequence - * resetbits - core specific bits that are set only during reset sequence - */ + void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) { @@ -587,14 +597,10 @@ ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ASSERT(GOODREGS(sii->curwrap)); ai = sii->curwrap; - /* - * Must do the disable sequence first to work for arbitrary current core state. - */ + ai_core_disable(sih, (bits | resetbits)); - /* - * Now do the initialization sequence. - */ + W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); dummy = R_REG(sii->osh, &ai->ioctrl); W_REG(sii->osh, &ai->resetctrl, 0); diff --git a/src/shared/bcmevent.c b/src/shared/bcmevent.c new file mode 100644 index 0000000..3cee7c2 --- /dev/null +++ b/src/shared/bcmevent.c @@ -0,0 +1,122 @@ +/* + * bcmevent read-only data shared by kernel or app layers + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 Exp $ + */ + +#include <typedefs.h> +#include <bcmutils.h> +#include <proto/ethernet.h> +#include <proto/bcmeth.h> +#include <proto/bcmevent.h> + +#if WLC_E_LAST != 84 +#error "You need to add an entry to bcmevent_names[] for the new event" +#endif + +const bcmevent_name_t bcmevent_names[] = { + { WLC_E_SET_SSID, "SET_SSID" }, + { WLC_E_JOIN, "JOIN" }, + { WLC_E_START, "START" }, + { WLC_E_AUTH, "AUTH" }, + { WLC_E_AUTH_IND, "AUTH_IND" }, + { WLC_E_DEAUTH, "DEAUTH" }, + { WLC_E_DEAUTH_IND, "DEAUTH_IND" }, + { WLC_E_ASSOC, "ASSOC" }, + { WLC_E_ASSOC_IND, "ASSOC_IND" }, + { WLC_E_REASSOC, "REASSOC" }, + { WLC_E_REASSOC_IND, "REASSOC_IND" }, + { WLC_E_DISASSOC, "DISASSOC" }, + { WLC_E_DISASSOC_IND, "DISASSOC_IND" }, + { WLC_E_QUIET_START, "START_QUIET" }, + { WLC_E_QUIET_END, "END_QUIET" }, + { WLC_E_BEACON_RX, "BEACON_RX" }, + { WLC_E_LINK, "LINK" }, + { WLC_E_MIC_ERROR, "MIC_ERROR" }, + { WLC_E_NDIS_LINK, "NDIS_LINK" }, + { WLC_E_ROAM, "ROAM" }, + { WLC_E_TXFAIL, "TXFAIL" }, + { WLC_E_PMKID_CACHE, "PMKID_CACHE" }, + { WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" }, + { WLC_E_PRUNE, "PRUNE" }, + { WLC_E_AUTOAUTH, "AUTOAUTH" }, + { WLC_E_EAPOL_MSG, "EAPOL_MSG" }, + { WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE" }, + { WLC_E_ADDTS_IND, "ADDTS_IND" }, + { WLC_E_DELTS_IND, "DELTS_IND" }, + { WLC_E_BCNSENT_IND, "BCNSENT_IND" }, + { WLC_E_BCNRX_MSG, "BCNRX_MSG" }, + { WLC_E_BCNLOST_MSG, "BCNLOST_IND" }, + { WLC_E_ROAM_PREP, "ROAM_PREP" }, + { WLC_E_PFN_NET_FOUND, "PFNFOUND_IND" }, + { WLC_E_PFN_NET_LOST, "PFNLOST_IND" }, +#if defined(IBSS_PEER_DISCOVERY_EVENT) + { WLC_E_IBSS_ASSOC, "IBSS_ASSOC" }, +#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ + { WLC_E_RADIO, "RADIO" }, + { WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG" }, + { WLC_E_PROBREQ_MSG, "PROBE_REQ_MSG" }, + { WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" }, + { WLC_E_PSK_SUP, "PSK_SUP" }, + { WLC_E_COUNTRY_CODE_CHANGED, "CNTRYCODE_IND" }, + { WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" }, + { WLC_E_ICV_ERROR, "ICV_ERROR" }, + { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, + { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, + { WLC_E_TRACE, "TRACE" }, + { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" }, + { WLC_E_IF, "IF" }, +#ifdef WLP2P + { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" }, +#endif + { WLC_E_RSSI, "RSSI" }, + { WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE" }, + { WLC_E_EXTLOG_MSG, "EXTERNAL LOG MESSAGE" }, +#ifdef WIFI_ACT_FRAME + { WLC_E_ACTION_FRAME, "ACTION_FRAME" }, + { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" }, + { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, +#endif + { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" }, + { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" }, +#ifdef WLP2P + { WLC_E_PROBRESP_MSG, "PROBE_RESP_MSG" }, + { WLC_E_P2P_PROBREQ_MSG, "P2P PROBE_REQ_MSG" }, +#endif +#ifdef PROP_TXSTATUS + { WLC_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP" }, +#endif + { WLC_E_WAKE_EVENT, "WAKE_EVENT" }, + { WLC_E_DCS_REQUEST, "DCS_REQUEST" }, + { WLC_E_RM_COMPLETE, "RM_COMPLETE" }, +#ifdef WLMEDIA_HTSF + { WLC_E_HTSFSYNC, "HTSF_SYNC_EVENT" }, +#endif + { WLC_E_OVERLAY_REQ, "OVERLAY_REQ_EVENT" }, + { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND" }, + { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" }, + { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, + { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" } +}; + + +const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); diff --git a/src/shared/bcmutils.c b/src/shared/bcmutils.c index 05a8cc1..fbdd7cd 100644 --- a/src/shared/bcmutils.c +++ b/src/shared/bcmutils.c @@ -1,7 +1,7 @@ /* * Driver O/S-independent utility routines * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,30 +20,46 @@ * 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.16.4 2009/07/13 18:04:07 Exp $ + * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $ */ #include <typedefs.h> #include <bcmdefs.h> #include <stdarg.h> -#include <bcmutils.h> + #ifdef BCMDRIVER + #include <osl.h> +#include <bcmutils.h> #include <siutils.h> -#else + +#else /* !BCMDRIVER */ + #include <stdio.h> #include <string.h> -#endif /* BCMDRIVER */ +#include <bcmutils.h> + +#if defined(BCMEXTSUP) +#include <bcm_osl.h> +#endif + + +#endif /* !BCMDRIVER */ + #include <bcmendian.h> #include <bcmdevs.h> #include <proto/ethernet.h> #include <proto/vlan.h> #include <proto/bcmip.h> #include <proto/802.1d.h> +#include <proto/802.11.h> +void *_bcmutils_dummy_fn = NULL; #ifdef BCMDRIVER + + /* copy a pkt buffer chain into a buffer */ uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) @@ -51,7 +67,7 @@ pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) uint n, ret = 0; if (len < 0) - len = 4096; /* "infinite" */ + len = 4096; /* "infinite" */ /* skip 'offset' bytes */ for (; p && offset; p = PKTNEXT(osh, p)) { @@ -108,7 +124,7 @@ pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) /* return total length of buffer chain */ -uint +uint BCMFASTPATH pkttotlen(osl_t *osh, void *p) { uint total; @@ -130,7 +146,7 @@ pktlast(osl_t *osh, void *p) } /* count segments of a chained packet */ -uint +uint BCMFASTPATH pktsegcnt(osl_t *osh, void *p) { uint cnt; @@ -146,7 +162,7 @@ pktsegcnt(osl_t *osh, void *p) * osl multiple-precedence packet queue * hi_prec is always >= the number of the highest non-empty precedence */ -void * +void * BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p) { struct pktq_prec *q; @@ -175,7 +191,7 @@ pktq_penq(struct pktq *pq, int prec, void *p) return p; } -void * +void * BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p) { struct pktq_prec *q; @@ -203,7 +219,7 @@ pktq_penq_head(struct pktq *pq, int prec, void *p) return p; } -void * +void * BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) { struct pktq_prec *q; @@ -228,7 +244,7 @@ pktq_pdeq(struct pktq *pq, int prec) return p; } -void * +void * BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) { struct pktq_prec *q; @@ -258,26 +274,38 @@ pktq_pdeq_tail(struct pktq *pq, int prec) } void -pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) +pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) { struct pktq_prec *q; - void *p; + void *p, *prev = NULL; q = &pq->q[prec]; p = q->head; while (p) { - q->head = PKTLINK(p); - PKTSETLINK(p, NULL); - PKTFREE(osh, p, dir); - q->len--; - pq->len--; - p = q->head; + if (fn == NULL || (*fn)(p, arg)) { + bool head = (p == q->head); + if (head) + q->head = PKTLINK(p); + else + PKTSETLINK(prev, PKTLINK(p)); + PKTSETLINK(p, NULL); + PKTFREE(osh, p, dir); + q->len--; + pq->len--; + p = (head ? q->head : PKTLINK(prev)); + } else { + prev = p; + p = PKTLINK(p); + } + } + + if (q->head == NULL) { + ASSERT(q->len == 0); + q->tail = NULL; } - ASSERT(q->len == 0); - q->tail = NULL; } -bool +bool BCMFASTPATH pktq_pdel(struct pktq *pq, void *pktbuf, int prec) { struct pktq_prec *q; @@ -328,7 +356,7 @@ pktq_init(struct pktq *pq, int num_prec, int max_len) pq->q[prec].max = pq->max; } -void * +void * BCMFASTPATH pktq_deq(struct pktq *pq, int *prec_out) { struct pktq_prec *q; @@ -361,7 +389,7 @@ pktq_deq(struct pktq *pq, int *prec_out) return p; } -void * +void * BCMFASTPATH pktq_deq_tail(struct pktq *pq, int *prec_out) { struct pktq_prec *q; @@ -437,12 +465,13 @@ pktq_peek_tail(struct pktq *pq, int *prec_out) } void -pktq_flush(osl_t *osh, struct pktq *pq, bool dir) +pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) { int prec; for (prec = 0; prec < pq->num_prec; prec++) - pktq_pflush(osh, pq, prec, dir); - ASSERT(pq->len == 0); + pktq_pflush(osh, pq, prec, dir, fn, arg); + if (fn == NULL) + ASSERT(pq->len == 0); } /* Return sum of lengths of a specific set of precedences */ @@ -461,7 +490,7 @@ pktq_mlen(struct pktq *pq, uint prec_bmp) } /* Priority dequeue from a specific set of precedences */ -void * +void * BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) { struct pktq_prec *q; @@ -497,41 +526,42 @@ pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) return p; } -#endif /* BCMDRIVER */ +#endif /* BCMDRIVER */ const unsigned char bcm_ctype[] = { - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ + + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, - _BCM_C, /* 8-15 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ - _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ - _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ - _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ - _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ + _BCM_C, /* 8-15 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ + _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ + _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ + _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ + _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ + _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ + _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ + _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ + _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ + _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ }; @@ -572,17 +602,18 @@ bcm_strtoul(char *cp, char **endp, uint base) result = 0; while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { + (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) + { result = result*base + value; /* Detected overflow */ if (result < last_result && !minus) - return ((unsigned long) -1); + return (ulong)-1; last_result = result; cp++; } if (minus) - result = (ulong)(result * -1); + result = (ulong)(-(long)result); if (endp) *endp = (char *)cp; @@ -663,7 +694,8 @@ bcmstrncat(char *dest, const char *src, uint size) * Returns: Pointer to the next token found. NULL when no more tokens are found. ***************************************************************************** */ -char* bcmstrtok(char **string, const char *delimiters, char *tokdelim) +char * +bcmstrtok(char **string, const char *delimiters, char *tokdelim) { unsigned char *str; unsigned long map[8]; @@ -740,7 +772,8 @@ char* bcmstrtok(char **string, const char *delimiters, char *tokdelim) * t1 > t2, when ignoring case sensitivity. ***************************************************************************** */ -int bcmstricmp(const char *s1, const char *s2) +int +bcmstricmp(const char *s1, const char *s2) { char dc, sc; @@ -773,7 +806,8 @@ int bcmstricmp(const char *s1, const char *s2) * t1 > t2, when ignoring case sensitivity. ***************************************************************************** */ -int bcmstrnicmp(const char* s1, const char* s2, int cnt) +int +bcmstrnicmp(const char* s1, const char* s2, int cnt) { char dc, sc; @@ -808,18 +842,14 @@ bcm_ether_atoe(char *p, struct ether_addr *ea) return (i == 6); } + #if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) /* registry routine buffer preparation utility functions: * parameter order is like strncpy, but returns count * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) */ ulong -wchar2ascii( - char *abuf, - ushort *wbuf, - ushort wbuflen, - ulong abuflen -) +wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) { ulong copyct = 1; ushort i; @@ -856,7 +886,7 @@ char * bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) { snprintf(buf, 16, "%d.%d.%d.%d", - ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); + ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); return (buf); } @@ -876,7 +906,6 @@ bcm_mdelay(uint ms) - #if defined(DHD_DEBUG) /* pretty hex print a pkt buffer chain */ void @@ -890,13 +919,13 @@ prpkt(const char *msg, osl_t *osh, void *p0) for (p = p0; p; p = PKTNEXT(osh, p)) prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); } -#endif +#endif /* Takes an Ethernet frame and sets out-of-bound PKTPRIO. * Also updates the inplace vlan tag if requested. * For debugging, it returns an indication of what it did. */ -uint +uint BCMFASTPATH pktsetprio(void *pkt, bool update_vtag) { struct ether_header *eh; @@ -921,7 +950,7 @@ pktsetprio(void *pkt, bool update_vtag) if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); - uint8 tos_tc = IP_TOS(ip_body); + uint8 tos_tc = IP_TOS46(ip_body); dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); } @@ -948,7 +977,7 @@ pktsetprio(void *pkt, bool update_vtag) } } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { uint8 *ip_body = pktdata + sizeof(struct ether_header); - uint8 tos_tc = IP_TOS(ip_body); + uint8 tos_tc = IP_TOS46(ip_body); priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); rc |= PKTPRIO_DSCP; } @@ -958,8 +987,9 @@ pktsetprio(void *pkt, bool update_vtag) return (rc | priority); } -static char bcm_undeferrstr[BCME_STRLEN]; +#ifndef BCM_BOOTLOADER +static char bcm_undeferrstr[32]; static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; /* Convert the error codes into related error strings */ @@ -970,7 +1000,7 @@ bcmerrorstr(int bcmerror) ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); if (bcmerror > 0 || bcmerror < BCME_LAST) { - snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror); + snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); return bcm_undeferrstr; } @@ -979,6 +1009,8 @@ bcmerrorstr(int bcmerror) return bcmerrorstrtable[-bcmerror]; } +#endif /* !BCM_BOOTLOADER */ + /* iovar table lookup */ @@ -1052,7 +1084,7 @@ bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) return bcmerror; } -#endif /* BCMDRIVER */ +#endif /* BCMDRIVER */ /******************************************************************************* @@ -1078,38 +1110,38 @@ bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) */ static const uint8 crc8_table[256] = { - 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, - 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, - 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, - 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, - 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, - 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, - 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, - 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, - 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, - 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, - 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, - 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, - 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, - 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, - 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, - 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, - 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, - 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, - 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, - 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, - 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, - 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, - 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, - 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, - 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, - 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, - 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, - 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, - 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, - 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, - 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, - 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F }; #define CRC_INNER_LOOP(n, c, x) \ @@ -1117,9 +1149,9 @@ static const uint8 crc8_table[256] = { uint8 hndcrc8( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint8 crc /* either CRC8_INIT_VALUE or previous return value */ + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint8 crc /* either CRC8_INIT_VALUE or previous return value */ ) { /* hard code the crc loop instead of using CRC_INNER_LOOP macro @@ -1154,45 +1186,45 @@ hndcrc8( */ static const uint16 crc16_table[256] = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 }; uint16 hndcrc16( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint16 crc /* either CRC16_INIT_VALUE or previous return value */ + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint16 crc /* either CRC16_INIT_VALUE or previous return value */ ) { while (nbytes-- > 0) @@ -1201,78 +1233,78 @@ hndcrc16( } static const uint32 crc32_table[256] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; +/* + * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if + * accumulating over multiple pieces. + */ uint32 -hndcrc32( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint32 crc /* either CRC32_INIT_VALUE or previous return value */ -) +hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) { uint8 *pend; #ifdef __mips__ @@ -1310,11 +1342,12 @@ hndcrc32( } #ifdef notdef -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) -#define CNBUFS 5 /* # of bufs */ +#define CLEN 1499 /* CRC Length */ +#define CBUFSIZ (CLEN+4) +#define CNBUFS 5 /* # of bufs */ -void testcrc32(void) +void +testcrc32(void) { uint j, k, l; uint8 *buf; @@ -1444,7 +1477,7 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) int i; char* p = buf; char hexstr[16]; - int slen = 0; + int slen = 0, nlen = 0; uint32 bit; const char* name; @@ -1452,39 +1485,48 @@ bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) return 0; buf[0] = '\0'; - len -= 1; for (i = 0; flags != 0; i++) { bit = bd[i].bit; name = bd[i].name; - if (bit == 0 && flags) { + if (bit == 0 && flags != 0) { /* print any unnamed bits */ - sprintf(hexstr, "0x%X", flags); + snprintf(hexstr, 16, "0x%X", flags); name = hexstr; - flags = 0; /* exit loop */ + flags = 0; /* exit loop */ } else if ((flags & bit) == 0) continue; - slen += strlen(name); - if (len < slen) - break; - if (p != buf) p += sprintf(p, " "); /* btwn flag space */ - strcat(p, name); - p += strlen(name); flags &= ~bit; + nlen = strlen(name); + slen += nlen; + /* count btwn flag space */ + if (flags != 0) + slen += 1; + /* need NULL char as well */ + if (len <= slen) + break; + /* copy NULL char but don't count it */ + strncpy(p, name, nlen + 1); + p += nlen; + /* copy btwn flag space and NULL char */ + if (flags != 0) + p += snprintf(p, 2, " "); len -= slen; - slen = 1; /* account for btwn flag space */ } /* indicate the str was too short */ if (flags != 0) { - if (len == 0) - p--; /* overwrite last char */ - p += sprintf(p, ">"); + if (len < 2) + p -= 2 - len; /* overwrite last char */ + p += snprintf(p, 2, ">"); } return (int)(p - buf); } +#endif +#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ + defined(DHD_DEBUG) || defined(WLMEDIA_PEAKRATE) /* print bytes formatted as hex to a string. return the resulting string length */ int bcm_format_hex(char *str, const void *bytes, int len) @@ -1494,7 +1536,7 @@ bcm_format_hex(char *str, const void *bytes, int len) const uint8 *src = (const uint8*)bytes; for (i = 0; i < len; i++) { - p += sprintf(p, "%02X", *src); + p += snprintf(p, 3, "%02X", *src); src++; } return (int)(p - str); @@ -1506,6 +1548,8 @@ void prhex(const char *msg, uchar *buf, uint nbytes) { char line[128], *p; + int len = sizeof(line); + int nchar; uint i; if (msg && (msg[0] != '\0')) @@ -1514,12 +1558,20 @@ prhex(const char *msg, uchar *buf, uint nbytes) p = line; for (i = 0; i < nbytes; i++) { if (i % 16 == 0) { - p += sprintf(p, " %04d: ", i); /* line prefix */ + nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ + p += nchar; + len -= nchar; + } + if (len > 0) { + nchar = snprintf(p, len, "%02x ", buf[i]); + p += nchar; + len -= nchar; } - p += sprintf(p, "%02x ", buf[i]); + if (i % 16 == 15) { - printf("%s\n", line); /* flush line */ + printf("%s\n", line); /* flush line */ p = line; + len = sizeof(line); } } @@ -1528,6 +1580,37 @@ prhex(const char *msg, uchar *buf, uint nbytes) printf("%s\n", line); } +static const char *crypto_algo_names[] = { + "NONE", + "WEP1", + "TKIP", + "WEP128", + "AES_CCM", + "AES_OCB_MSDU", + "AES_OCB_MPDU", + "NALG" + "UNDEF", + "UNDEF", + "UNDEF", + "UNDEF" +}; + +const char * +bcm_crypto_algo_name(uint algo) +{ + return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; +} + + +char * +bcm_chipname(uint chipid, char *buf, uint len) +{ + const char *fmt; + + fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + snprintf(buf, len, fmt, chipid); + return buf; +} /* Produce a human-readable string for boardrev */ char * @@ -1584,7 +1667,7 @@ bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc if (cur_ptr->nameandfmt == NULL) break; len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); + read_rtn(arg0, arg1, cur_ptr->offset)); /* check for snprintf overflow or error */ if (len < 0 || (uint32)len >= bufsize) len = bufsize - 1; @@ -1615,15 +1698,14 @@ bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) return len; } - /* Quarter dBm units to mW * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 * Table is offset so the last entry is largest mW value that fits in * a uint16. */ -#define QDBM_OFFSET 153 /* Offset for first entry */ -#define QDBM_TABLE_LEN 40 /* Table size */ +#define QDBM_OFFSET 153 /* Offset for first entry */ +#define QDBM_TABLE_LEN 40 /* Table size */ /* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 @@ -1637,12 +1719,12 @@ bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) #define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { -/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ -/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, -/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, -/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, -/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, -/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 +/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ +/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, +/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, +/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, +/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, +/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 }; uint16 @@ -1692,8 +1774,9 @@ bcm_mw_to_qdbm(uint16 mw) for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - - nqdBm_to_mW_map[qdbm])/2; - if (mw_uint < boundary) break; + nqdBm_to_mW_map[qdbm])/2; + if (mw_uint < boundary) + break; } qdbm += (uint8)offset; @@ -1717,7 +1800,6 @@ bcm_bitcount(uint8 *bitmap, uint length) return bitcount; } - #ifdef BCMDRIVER /* Initialization of bcmstrbuf structure */ @@ -1796,5 +1878,90 @@ bcm_print_bytes(char *name, const uchar *data, int len) } printf("\n"); } +#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ + defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) +#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) + +int +bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) +{ + uint i, c; + char *p = buf; + char *endp = buf + SSID_FMT_BUF_LEN; + + if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; + + for (i = 0; i < ssid_len; i++) { + c = (uint)ssid[i]; + if (c == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else if (bcm_isprint((uchar)c)) { + *p++ = (char)c; + } else { + p += snprintf(p, (endp - p), "\\x%02X", c); + } + } + *p = '\0'; + ASSERT(p < endp); + + return (int)(p - buf); +} +#endif #endif /* BCMDRIVER */ + +/* + * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. + * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0 + * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. + * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. +*/ + +unsigned int +process_nvram_vars(char *varbuf, unsigned int len) +{ + char *dp; + bool findNewline; + int column; + unsigned int buf_len, n; + unsigned int pad = 0; + + dp = varbuf; + + findNewline = FALSE; + column = 0; + + for (n = 0; n < len; n++) { + if (varbuf[n] == '\r') + continue; + if (findNewline && varbuf[n] != '\n') + continue; + findNewline = FALSE; + if (varbuf[n] == '#') { + findNewline = TRUE; + continue; + } + if (varbuf[n] == '\n') { + if (column == 0) + continue; + *dp++ = 0; + column = 0; + continue; + } + *dp++ = varbuf[n]; + column++; + } + buf_len = (unsigned int)(dp - varbuf); + if (buf_len % 4) { + pad = 4 - buf_len % 4; + if (pad && (buf_len + pad <= len)) { + buf_len += pad; + } + } + + while (dp < varbuf + n) + *dp++ = 0; + + return buf_len; +} diff --git a/src/shared/bcmwifi.c b/src/shared/bcmwifi.c index 006530f..7072217 100644 --- a/src/shared/bcmwifi.c +++ b/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-2011, 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.c,v 1.18.24.2.18.1 2009/07/09 00:07:48 Exp $ + * $Id: bcmwifi.c,v 1.31.8.1 2010-08-03 17:47:05 Exp $ */ @@ -37,6 +37,9 @@ #include <stdio.h> #include <stdlib.h> #include <ctype.h> +#ifndef ASSERT +#define ASSERT(exp) +#endif #endif #include <bcmwifi.h> @@ -44,10 +47,6 @@ #include <bcmstdlib.h> #endif -#ifndef ASSERT -#define ASSERT -#endif - @@ -87,7 +86,7 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf) chanspec_t wf_chspec_aton(char *a) { - char *endp; + char *endp = NULL; uint channel, band, bw, ctl_sb; char c; @@ -158,7 +157,7 @@ wf_chspec_malformed(chanspec_t chanspec) return TRUE; - if (CHSPEC_IS20(chanspec)) { + if (CHSPEC_IS20_UNCOND(chanspec)) { if (!CHSPEC_SB_NONE(chanspec)) return TRUE; } else { @@ -218,6 +217,7 @@ wf_chspec_ctlchspec(chanspec_t chspec) return ctl_chspec; } + int wf_mhz2channel(uint freq, uint start_factor) { @@ -263,9 +263,9 @@ wf_channel2mhz(uint ch, uint start_factor) int freq; if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || - (ch <= 200)) + (ch > 200)) freq = -1; - if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) + else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) freq = 2484; else freq = ch * 5 + start_factor / 2; diff --git a/src/shared/hndpmu.c b/src/shared/hndpmu.c index ce1b320..b9586e4 100644 --- a/src/shared/hndpmu.c +++ b/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-2011, 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.13.4.14 2009/09/14 16:03:39 Exp $ + * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $ */ #include <typedefs.h> @@ -35,13 +35,19 @@ #include <sbchipc.h> #include <hndpmu.h> -/* debug/trace */ #define PMU_ERROR(args) #define PMU_MSG(args) +/* To check in verbose debugging messages not intended + * to be on except on private builds. + */ +#define PMU_NONE(args) + -/* SDIO Pad drive strength to select value mappings */ +/* SDIO Pad drive strength to select value mappings. + * The last strength value in each table must be 0 (the tri-state value). + */ typedef struct { uint8 strength; /* Pad Drive Strength in mA */ uint8 sel; /* Chip-specific select value */ @@ -64,13 +70,78 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { {2, 0x1}, {0, 0x0} }; +/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { + {32, 0x7}, + {26, 0x6}, + {22, 0x5}, + {16, 0x4}, + {12, 0x3}, + {8, 0x2}, + {4, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { + {32, 0x6}, + {26, 0x7}, + {22, 0x4}, + {16, 0x5}, + {12, 0x2}, + {8, 0x3}, + {4, 0x0}, + {0, 0x1} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = { + {16, 0x3}, + {13, 0x2}, + {11, 0x1}, + {8, 0x0}, + {6, 0x7}, + {4, 0x6}, + {2, 0x5}, + {0, 0x4} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = { + {80, 0x5}, + {65, 0x4}, + {55, 0x7}, + {40, 0x6}, + {30, 0x1}, + {20, 0x0}, + {10, 0x3}, + {0, 0x2} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { + {6, 0x7}, + {5, 0x6}, + {4, 0x5}, + {3, 0x4}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ +static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = { + {12, 0x7}, + {10, 0x6}, + {8, 0x5}, + {6, 0x4}, + {4, 0x2}, + {2, 0x1}, + {0, 0x0} }; + + #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { chipcregs_t *cc; - uint origidx, intr_val; + uint origidx, intr_val = 0; sdiod_drive_str_t *str_tab = NULL; uint32 str_mask = 0; uint32 str_shift = 0; @@ -95,35 +166,55 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) str_mask = 0x00003800; str_shift = 11; break; - + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): + if (sih->pmurev == 8) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; + } + else if (sih->pmurev == 11) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + } + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; default: - PMU_MSG(("No SDIO Drive strength init done for chip %x rev %d pmurev %d\n", - sih->chip, sih->chiprev, sih->pmurev)); + PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); break; } if (str_tab != NULL) { - uint32 drivestrength_sel = 0; uint32 cc_data_temp; int i; - for (i = 0; str_tab[i].strength != 0; i ++) { - if (drivestrength >= str_tab[i].strength) { - drivestrength_sel = str_tab[i].sel; - break; - } - } + /* Pick the lowest available drive strength equal or greater than the + * requested strength. Drive strength of 0 requests tri-state. + */ + for (i = 0; drivestrength < str_tab[i].strength; i++) + ; + + if (i > 0 && drivestrength > str_tab[i].strength) + i--; W_REG(osh, &cc->chipcontrol_addr, 1); cc_data_temp = R_REG(osh, &cc->chipcontrol_data); cc_data_temp &= ~str_mask; - drivestrength_sel <<= str_shift; - cc_data_temp |= drivestrength_sel; + cc_data_temp |= str_tab[i].sel << str_shift; W_REG(osh, &cc->chipcontrol_data, cc_data_temp); - PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n", - drivestrength, cc_data_temp)); + PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", + drivestrength, str_tab[i].strength)); } /* Return to original core */ diff --git a/src/shared/linux_osl.c b/src/shared/linux_osl.c index 7ab1bbe..14b9aa1 100644 --- a/src/shared/linux_osl.c +++ b/src/shared/linux_osl.c @@ -1,7 +1,7 @@ /* * Linux OS Independent Layer * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,11 +21,11 @@ * 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.22.4 2009/10/09 01:44:27 Exp $ + * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 Exp $ */ -#define LINUX_OSL +#define LINUX_PORT #include <typedefs.h> #include <bcmendian.h> @@ -36,11 +36,39 @@ #include <linux/delay.h> #include <pcicfg.h> +#ifdef BCMASSERT_LOG +#include <bcm_assert_log.h> +#endif + +#include <linux/fs.h> + #define PCI_CFG_RETRY 10 #define OS_HANDLE_MAGIC 0x1234abcd #define BCM_MEM_FILENAME_LEN 24 +#ifdef DHD_USE_STATIC_BUF +#define MAX_STATIC_BUF_NUM 16 +#define STATIC_BUF_SIZE (PAGE_SIZE*2) +#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE) +typedef struct bcm_static_buf { + struct semaphore static_sem; + unsigned char *buf_ptr; + unsigned char buf_use[MAX_STATIC_BUF_NUM]; +} bcm_static_buf_t; + +static bcm_static_buf_t *bcm_static_buf = 0; + +#define MAX_STATIC_PKT_NUM 8 +typedef struct bcm_static_pkt { + struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM]; + struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM]; + struct semaphore osl_pkt_sem; + unsigned char pkt_use[MAX_STATIC_PKT_NUM*2]; +} bcm_static_pkt_t; +static bcm_static_pkt_t *bcm_static_skb = 0; +#endif + typedef struct bcm_mem_link { struct bcm_mem_link *prev; struct bcm_mem_link *next; @@ -51,15 +79,23 @@ typedef struct bcm_mem_link { struct osl_info { osl_pubinfo_t pub; +#ifdef CTFPOOL + ctfpool_t *ctfpool; +#endif uint magic; void *pdev; - uint malloced; + atomic_t malloced; uint failed; uint bustype; bcm_mem_link_t *dbgmem_list; }; -static int16 linuxbcmerrormap[] = \ + + + +uint32 g_assert_type = FALSE; + +static int16 linuxbcmerrormap[] = { 0, -EINVAL, -EINVAL, @@ -97,14 +133,19 @@ static int16 linuxbcmerrormap[] = \ -EINVAL, -EIO, -ENODEV, - -EINVAL + -EINVAL, + -EIO, + -EIO, + -ENODEV, + -EINVAL, + -ENODATA, -#if BCME_LAST != -37 +#if BCME_LAST != -42 #error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmuitls.h" -#endif + for new error code defined in bcmutils.h" +#endif }; @@ -120,6 +161,7 @@ osl_error(int bcmerror) return linuxbcmerrormap[-bcmerror]; } +void * dhd_os_prealloc(int section, unsigned long size); osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { @@ -134,7 +176,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag) ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); osh->magic = OS_HANDLE_MAGIC; - osh->malloced = 0; + atomic_set(&osh->malloced, 0); osh->failed = 0; osh->dbgmem_list = NULL; osh->pdev = pdev; @@ -151,6 +193,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag) case SDIO_BUS: case USB_BUS: case SPI_BUS: + case RPC_BUS: osh->pub.mmbus = FALSE; break; default: @@ -158,6 +201,38 @@ osl_attach(void *pdev, uint bustype, bool pkttag) break; } +#ifdef DHD_USE_STATIC_BUF + if (!bcm_static_buf) { + if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+ + STATIC_BUF_TOTAL_LEN))) { + printk("can not alloc static buf!\n"); + } + else + printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); + + + sema_init(&bcm_static_buf->static_sem, 1); + + + bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; + + } + + if (!bcm_static_skb) + { + int i; + void *skb_buff_ptr = 0; + bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); + skb_buff_ptr = dhd_os_prealloc(4, 0); + + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16); + for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++) + bcm_static_skb->pkt_use[i] = 0; + + sema_init(&bcm_static_skb->osl_pkt_sem, 1); + } +#endif + return osh; } @@ -171,13 +246,201 @@ osl_detach(osl_t *osh) kfree(osh); } +#ifdef CTFPOOL -void* +void * +osl_ctfpool_add(osl_t *osh) +{ + struct sk_buff *skb; + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return NULL; + + spin_lock_bh(&osh->ctfpool->lock); + ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); + + + if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { + spin_unlock_bh(&osh->ctfpool->lock); + return NULL; + } + + + skb = dev_alloc_skb(osh->ctfpool->obj_size); + if (skb == NULL) { + printf("%s: skb alloc of len %d failed\n", __FUNCTION__, + osh->ctfpool->obj_size); + spin_unlock_bh(&osh->ctfpool->lock); + return NULL; + } + + + skb->next = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = skb; + osh->ctfpool->fast_frees++; + osh->ctfpool->curr_obj++; + + + CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; + + + PKTFAST(osh, skb) = FASTBUF; + + spin_unlock_bh(&osh->ctfpool->lock); + + return skb; +} + + +void +osl_ctfpool_replenish(osl_t *osh, uint thresh) +{ + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + + while ((osh->ctfpool->refills > 0) && (thresh--)) { + osl_ctfpool_add(osh); + osh->ctfpool->refills--; + } +} + + +int32 +osl_ctfpool_init(osl_t *osh, uint numobj, uint size) +{ + osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); + ASSERT(osh->ctfpool); + bzero(osh->ctfpool, sizeof(ctfpool_t)); + + osh->ctfpool->max_obj = numobj; + osh->ctfpool->obj_size = size; + + spin_lock_init(&osh->ctfpool->lock); + + while (numobj--) { + if (!osl_ctfpool_add(osh)) + return -1; + osh->ctfpool->fast_frees--; + } + + return 0; +} + + +void +osl_ctfpool_cleanup(osl_t *osh) +{ + struct sk_buff *skb, *nskb; + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + + spin_lock_bh(&osh->ctfpool->lock); + + skb = osh->ctfpool->head; + + while (skb != NULL) { + nskb = skb->next; + dev_kfree_skb(skb); + skb = nskb; + osh->ctfpool->curr_obj--; + } + + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->head = NULL; + spin_unlock_bh(&osh->ctfpool->lock); + + kfree(osh->ctfpool); + osh->ctfpool = NULL; +} + +void +osl_ctfpool_stats(osl_t *osh, void *b) +{ + struct bcmstrbuf *bb; + + if ((osh == NULL) || (osh->ctfpool == NULL)) + return; + +#ifdef DHD_USE_STATIC_BUF + if (bcm_static_buf) { + bcm_static_buf = 0; + } + if (bcm_static_skb) { + bcm_static_skb = 0; + } +#endif + + bb = b; + + ASSERT((osh != NULL) && (bb != NULL)); + + bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", + osh->ctfpool->max_obj, osh->ctfpool->obj_size, + osh->ctfpool->curr_obj, osh->ctfpool->refills); + bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", + osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, + osh->ctfpool->slow_allocs); +} + +static inline struct sk_buff * +osl_pktfastget(osl_t *osh, uint len) +{ + struct sk_buff *skb; + + + if (osh->ctfpool == NULL) + return NULL; + + spin_lock_bh(&osh->ctfpool->lock); + if (osh->ctfpool->head == NULL) { + ASSERT(osh->ctfpool->curr_obj == 0); + osh->ctfpool->slow_allocs++; + spin_unlock_bh(&osh->ctfpool->lock); + return NULL; + } + + ASSERT(len <= osh->ctfpool->obj_size); + + + skb = (struct sk_buff *)osh->ctfpool->head; + osh->ctfpool->head = (void *)skb->next; + + osh->ctfpool->fast_allocs++; + osh->ctfpool->curr_obj--; + ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); + spin_unlock_bh(&osh->ctfpool->lock); + + + skb->next = skb->prev = NULL; + skb->data = skb->head + 16; + skb->tail = skb->head + 16; + + skb->len = 0; + skb->cloned = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) + skb->list = NULL; +#endif + atomic_set(&skb->users, 1); + + return skb; +} +#endif + + +void * BCMFASTPATH osl_pktget(osl_t *osh, uint len) { struct sk_buff *skb; +#ifdef CTFPOOL + + skb = osl_pktfastget(osh, len); + if ((skb != NULL) || ((skb = dev_alloc_skb(len)) != NULL)) { +#else if ((skb = dev_alloc_skb(len))) { +#endif skb_put(skb, len); skb->priority = 0; @@ -188,8 +451,43 @@ osl_pktget(osl_t *osh, uint len) return ((void*) skb); } +#ifdef CTFPOOL +static inline void +osl_pktfastfree(osl_t *osh, struct sk_buff *skb) +{ + ctfpool_t *ctfpool; + + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); -void + + spin_lock_bh(&ctfpool->lock); + skb->next = (struct sk_buff *)ctfpool->head; + ctfpool->head = (void *)skb; + + ctfpool->fast_frees++; + ctfpool->curr_obj++; + + ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); + spin_unlock_bh(&ctfpool->lock); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) + skb->tstamp.tv.sec = 0; +#else + skb->stamp.tv_sec = 0; +#endif + + + skb->dev = NULL; + skb->dst = NULL; + memset(skb->cb, 0, sizeof(skb->cb)); + skb->ip_summed = 0; + skb->destructor = NULL; +} +#endif + + +void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) { struct sk_buff *skb, *nskb; @@ -205,12 +503,20 @@ osl_pktfree(osl_t *osh, void *p, bool send) skb->next = NULL; - if (skb->destructor) { - - dev_kfree_skb_any(skb); - } else { - - dev_kfree_skb(skb); +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) + osl_pktfastfree(osh, skb); + else { +#else + { +#endif + + if (skb->destructor) + + dev_kfree_skb_any(skb); + else + + dev_kfree_skb(skb); } osh->pub.pktalloced--; @@ -219,6 +525,89 @@ osl_pktfree(osl_t *osh, void *p, bool send) } } +#ifdef DHD_USE_STATIC_BUF +void* +osl_pktget_static(osl_t *osh, uint len) +{ + int i = 0; + struct sk_buff *skb; + + + if (len > (PAGE_SIZE*2)) + { + printk("Do we really need this big skb??\n"); + return osl_pktget(osh, len); + } + + + down(&bcm_static_skb->osl_pkt_sem); + if (len <= PAGE_SIZE) + { + + for (i = 0; i < MAX_STATIC_PKT_NUM; i++) + { + if (bcm_static_skb->pkt_use[i] == 0) + break; + } + + if (i != MAX_STATIC_PKT_NUM) + { + bcm_static_skb->pkt_use[i] = 1; + up(&bcm_static_skb->osl_pkt_sem); + + skb = bcm_static_skb->skb_4k[i]; + skb->tail = skb->data + len; + skb->len = len; + + return skb; + } + } + + + for (i = 0; i < MAX_STATIC_PKT_NUM; i++) + { + if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0) + break; + } + + if (i != MAX_STATIC_PKT_NUM) + { + bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1; + up(&bcm_static_skb->osl_pkt_sem); + skb = bcm_static_skb->skb_8k[i]; + skb->tail = skb->data + len; + skb->len = len; + + return skb; + } + + + up(&bcm_static_skb->osl_pkt_sem); + printk("all static pkt in use!\n"); + return osl_pktget(osh, len); +} + + +void +osl_pktfree_static(osl_t *osh, void *p, bool send) +{ + int i; + + for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++) + { + if (p == bcm_static_skb->skb_4k[i]) + { + down(&bcm_static_skb->osl_pkt_sem); + bcm_static_skb->pkt_use[i] = 0; + up(&bcm_static_skb->osl_pkt_sem); + + + return; + } + } + return osl_pktfree(osh, p, send); +} +#endif uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size) { @@ -295,9 +684,7 @@ osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); } - - -void* +void * osl_malloc(osl_t *osh, uint size) { void *addr; @@ -312,7 +699,7 @@ osl_malloc(osl_t *osh, uint size) return (NULL); } if (osh) - osh->malloced += size; + atomic_add(size, &osh->malloced); return (addr); } @@ -322,7 +709,7 @@ osl_mfree(osl_t *osh, void *addr, uint size) { if (osh) { ASSERT(osh->magic == OS_HANDLE_MAGIC); - osh->malloced -= size; + atomic_sub(size, &osh->malloced); } kfree(addr); } @@ -331,7 +718,7 @@ uint osl_malloced(osl_t *osh) { ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - return (osh->malloced); + return (atomic_read(&osh->malloced)); } uint @@ -341,11 +728,24 @@ osl_malloc_failed(osl_t *osh) return (osh->failed); } + + +uint +osl_dma_consistent_align(void) +{ + return (PAGE_SIZE); +} + void* -osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap) +osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) { + uint16 align = (1 << align_bits); ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) + size += align; + *alloced = size; + return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); } @@ -357,7 +757,7 @@ osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); } -uint +uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction) { int dir; @@ -367,7 +767,7 @@ osl_dma_map(osl_t *osh, void *va, uint size, int direction) return (pci_map_single(osh->pdev, va, size, dir)); } -void +void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) { int dir; @@ -377,6 +777,31 @@ osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) pci_unmap_single(osh->pdev, (uint32)pa, size, dir); } +#if defined(BCMASSERT_LOG) +void +osl_assert(char *exp, char *file, int line) +{ + char tempbuf[256]; + char *basename; + + basename = strrchr(file, '/'); + + if (basename) + basename++; + + if (!basename) + basename = file; + +#ifdef BCMASSERT_LOG + snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", + exp, basename, line); + + bcm_assert_log(tempbuf); +#endif + + +} +#endif void osl_delay(uint usec) @@ -400,6 +825,19 @@ osl_pktdup(osl_t *osh, void *skb) if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) return NULL; +#ifdef CTFPOOL + if (PKTISFAST(osh, skb)) { + ctfpool_t *ctfpool; + + + ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); + ASSERT(ctfpool != NULL); + PKTCLRFAST(osh, p); + PKTCLRFAST(osh, skb); + ctfpool->refills++; + } +#endif + if (osh->pub.pkttag) bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); @@ -408,3 +846,45 @@ osl_pktdup(osl_t *osh, void *skb) osh->pub.pktalloced++; return (p); } + + + + + + + +void * +osl_os_open_image(char *filename) +{ + struct file *fp; + + fp = filp_open(filename, O_RDONLY, 0); + + if (IS_ERR(fp)) + fp = NULL; + + return fp; +} + +int +osl_os_get_image_block(char *buf, int len, void *image) +{ + struct file *fp = (struct file *)image; + int rdlen; + + if (!image) + return 0; + + rdlen = kernel_read(fp, fp->f_pos, buf, len); + if (rdlen > 0) + fp->f_pos += rdlen; + + return rdlen; +} + +void +osl_os_close_image(void *image) +{ + if (image) + filp_close((struct file *)image, NULL); +} diff --git a/src/shared/miniopt.c b/src/shared/miniopt.c index 20a81f3..c7c19e8 100644 --- a/src/shared/miniopt.c +++ b/src/shared/miniopt.c @@ -1,7 +1,7 @@ /* * Description. * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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: miniopt.c,v 1.1.4.3 2009/01/14 23:45:48 Exp $ + * $Id: miniopt.c,v 1.8 2009-09-21 16:10:13 Exp $ */ /* ---- Include Files ---------------------------------------------------- */ @@ -29,7 +29,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "miniopt.h" +#include <miniopt.h> /* ---- Public Variables ------------------------------------------------- */ @@ -62,7 +62,7 @@ int miniopt(miniopt_t *t, char **argv) { int keylen; - char *p, *eq, *valstr, *endptr; + char *p, *eq, *valstr, *endptr = NULL; int err = 0; t->consumed = 0; diff --git a/src/shared/sbutils.c b/src/shared/sbutils.c index abbbd3a..02d1bc0 100644 --- a/src/shared/sbutils.c +++ b/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-2011, 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: sbutils.c,v 1.662.4.10.2.7 2008/08/06 03:43:24 Exp $ + * $Id: sbutils.c,v 1.687.2.1 2010-11-29 20:21:56 Exp $ */ #include <typedefs.h> @@ -38,6 +38,7 @@ #include "siutils_priv.h" + /* local prototypes */ static uint _sb_coreidx(si_info_t *sii, uint32 sba); static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, @@ -111,17 +112,10 @@ sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) } if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { -#ifdef IL_BIGENDIAN - dummy = R_REG(sii->osh, sbr); - W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); - dummy = R_REG(sii->osh, sbr); - W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); -#else dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); dummy = R_REG(sii->osh, sbr); W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); -#endif /* IL_BIGENDIAN */ } else W_REG(sii->osh, sbr, v); @@ -145,6 +139,28 @@ sb_coreid(si_t *sih) } uint +sb_intflag(si_t *sih) +{ + si_info_t *sii; + void *corereg; + sbconfig_t *sb; + uint origidx, intflag, intr_val = 0; + + sii = SI_INFO(sih); + + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + corereg = si_setcore(sih, CC_CORE_ID, 0); + ASSERT(corereg != NULL); + sb = REGS2SB(corereg); + intflag = R_SBREG(sii, &sb->sbflagst); + sb_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + + return intflag; +} + +uint sb_flag(si_t *sih) { si_info_t *sii; @@ -180,7 +196,7 @@ _sb_coreidx(si_info_t *sii, uint32 sba) uint i; for (i = 0; i < sii->numcores; i ++) - if (sba == sii->common_info->coresba[i]) + if (sba == sii->coresba[i]) return i; return BADIDX; } @@ -363,20 +379,23 @@ sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ASSERT(regoff < SI_CORE_SIZE); ASSERT((val & ~mask) == 0); + if (coreidx >= SI_MAXCORES) + return 0; + if (BUSTYPE(sii->pub.bustype) == SI_BUS) { /* If internal bus, we can always get at everything */ fast = TRUE; /* map if does not exist */ - if (!sii->common_info->regs[coreidx]) { - sii->common_info->regs[coreidx] = - REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE); - ASSERT(GOODREGS(sii->common_info->regs[coreidx])); + if (!sii->regs[coreidx]) { + sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], + SI_CORE_SIZE); + ASSERT(GOODREGS(sii->regs[coreidx])); } - r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff); + r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { /* Chipc registers are mapped at 12KB */ fast = TRUE; @@ -467,24 +486,23 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num * Core addresses must be contiguous on each bus. */ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { - sii->common_info->coresba[next] = sbba + (i * SI_CORE_SIZE); + sii->coresba[next] = sbba + (i * SI_CORE_SIZE); /* keep and reuse the initial register mapping */ - if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && - (sii->common_info->coresba[next] == sba)) { - SI_MSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); - sii->common_info->regs[next] = regs; + if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) { + SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); + sii->regs[next] = regs; } /* change core to 'next' and read its coreid */ sii->curmap = _sb_setcoreidx(sii, next); sii->curidx = next; - sii->common_info->coreid[next] = sb_coreid(&sii->pub); + sii->coreid[next] = sb_coreid(&sii->pub); /* core specific processing... */ /* chipc provides # cores */ - if (sii->common_info->coreid[next] == CC_CORE_ID) { + if (sii->coreid[next] == CC_CORE_ID) { chipcregs_t *cc = (chipcregs_t *)sii->curmap; uint32 ccrev = sb_corerev(&sii->pub); @@ -494,7 +512,7 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num CID_CC_SHIFT; else { /* Older chips */ - uint chip = sii->pub.chip; + uint chip = CHIPID(sii->pub.chip); if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ numcores = 6; @@ -509,11 +527,11 @@ _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint num numcores = 1; } } - SI_MSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, + SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, sii->pub.issim ? "QT" : "")); } /* scan bridged SB(s) and add results to the end of the list */ - else if (sii->common_info->coreid[next] == OCP_CORE_ID) { + else if (sii->coreid[next] == OCP_CORE_ID) { sbconfig_t *sb = REGS2SB(sii->curmap); uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); uint nsbcc; @@ -546,8 +564,12 @@ sb_scan(si_t *sih, void *regs, uint devid) { si_info_t *sii; uint32 origsba; + sbconfig_t *sb; sii = SI_INFO(sih); + sb = REGS2SB(sii->curmap); + + sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; /* Save the current core info and validate it later till we know * for sure what is good and what is bad. @@ -591,17 +613,17 @@ sb_setcoreidx(si_t *sih, uint coreidx) static void * _sb_setcoreidx(si_info_t *sii, uint coreidx) { - uint32 sbaddr = sii->common_info->coresba[coreidx]; + uint32 sbaddr = sii->coresba[coreidx]; void *regs; switch (BUSTYPE(sii->pub.bustype)) { case SI_BUS: /* map new one */ - if (!sii->common_info->regs[coreidx]) { - sii->common_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); - ASSERT(GOODREGS(sii->common_info->regs[coreidx])); + if (!sii->regs[coreidx]) { + sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); + ASSERT(GOODREGS(sii->regs[coreidx])); } - regs = sii->common_info->regs[coreidx]; + regs = sii->regs[coreidx]; break; case PCI_BUS: @@ -623,11 +645,11 @@ _sb_setcoreidx(si_info_t *sii, uint coreidx) case SPI_BUS: case SDIO_BUS: /* map new one */ - if (!sii->common_info->regs[coreidx]) { - sii->common_info->regs[coreidx] = (void *)(uintptr)sbaddr; - ASSERT(GOODREGS(sii->common_info->regs[coreidx])); + if (!sii->regs[coreidx]) { + sii->regs[coreidx] = (void *)(uintptr)sbaddr; + ASSERT(GOODREGS(sii->regs[coreidx])); } - regs = sii->common_info->regs[coreidx]; + regs = sii->regs[coreidx]; break; @@ -729,6 +751,7 @@ sb_commit(si_t *sih) /* switch over to chipcommon core if there is one, else use pci */ if (sii->pub.ccrev != NOREV) { chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(ccregs != NULL); /* do the buffer registers update */ W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); @@ -844,38 +867,6 @@ sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) OSL_DELAY(1); } -void -sb_core_tofixup(si_t *sih) -{ - si_info_t *sii; - sbconfig_t *sb; - - sii = SI_INFO(sih); - - if ((BUSTYPE(sii->pub.bustype) != PCI_BUS) || PCIE(sii) || - (PCI(sii) && (sii->pub.buscorerev >= 5))) - return; - - ASSERT(GOODREGS(sii->curmap)); - sb = REGS2SB(sii->curmap); - - if (BUSTYPE(sii->pub.bustype) == SI_BUS) { - SET_SBREG(sii, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x5 << SBIMCL_RTO_SHIFT) | 0x3); - } else { - if (sb_coreid(sih) == PCI_CORE_ID) { - SET_SBREG(sii, &sb->sbimconfiglow, - SBIMCL_RTO_MASK | SBIMCL_STO_MASK, - (0x3 << SBIMCL_RTO_SHIFT) | 0x2); - } else { - SET_SBREG(sii, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0); - } - } - - sb_commit(sih); -} - /* * Set the initiator timeout for the "master core". * The master core is defined to be the core in control diff --git a/src/shared/siutils.c b/src/shared/siutils.c index 005e725..22aa412 100644 --- a/src/shared/siutils.c +++ b/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-2011, 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.22.4.1 2008/12/22 01:19:31 Exp $ + * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $ */ #include <typedefs.h> @@ -41,6 +41,7 @@ #include <sbsdio.h> #include <sbhnddma.h> #include <sbsdpcmdev.h> +#include <bcmsdpcm.h> #include <hndpmu.h> #include "siutils_priv.h" @@ -55,7 +56,6 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint /* global variable to indicate reservation/release of gpio's */ static uint32 si_gpioreservation = 0; -static void *common_info_alloced = NULL; /* global flag to prevent shared resources from being initialized multiple times in si_attach() */ @@ -81,8 +81,6 @@ si_attach(uint devid, osl_t *osh, void *regs, } if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { - if (NULL != sii->common_info) - MFREE(osh, sii->common_info, sizeof(si_common_info_t)); MFREE(osh, sii, sizeof(si_info_t)); return (NULL); } @@ -104,14 +102,13 @@ si_kattach(osl_t *osh) static bool ksii_attached = FALSE; if (!ksii_attached) { - void *regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); + void *regs; + regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, SI_BUS, NULL, osh != SI_OSH ? &ksii.vars : NULL, osh != SI_OSH ? &ksii.varsz : NULL) == NULL) { - if (NULL != ksii.common_info) - MFREE(osh, ksii.common_info, sizeof(si_common_info_t)); SI_ERROR(("si_kattach: si_doattach failed\n")); REG_UNMAP(regs); return NULL; @@ -199,6 +196,10 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, /* get chipcommon capabilites */ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); + /* get chipcommon extended capabilities */ + + if (sii->pub.ccrev >= 35) + sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); /* get pmu rev and caps */ if (sii->pub.cccaps & CC_CAP_PMU) { @@ -227,8 +228,8 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, crev = si_corerev(&sii->pub); /* Display cores found */ - SI_MSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", - i, cid, crev, sii->common_info->coresba[i], sii->common_info->regs[i])); + SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", + i, cid, crev, sii->coresba[i], sii->regs[i])); if (BUSTYPE(bustype) == PCI_BUS) { if (cid == PCI_CORE_ID) { @@ -256,17 +257,26 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, } /* find the core idx before entering this func. */ - if ((savewin && (savewin == sii->common_info->coresba[i])) || - (regs == sii->common_info->regs[i])) + if ((savewin && (savewin == sii->coresba[i])) || + (regs == sii->regs[i])) *origidx = i; } + if (pci) { + sii->pub.buscoretype = PCI_CORE_ID; + sii->pub.buscorerev = pcirev; + sii->pub.buscoreidx = pciidx; + } else if (pcie) { + sii->pub.buscoretype = PCIE_CORE_ID; + sii->pub.buscorerev = pcierev; + sii->pub.buscoreidx = pcieidx; + } - SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, - sii->pub.buscorerev)); + SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, + sii->pub.buscorerev)); if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && - (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (sii->pub.chiprev <= 3)) + (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); @@ -286,6 +296,7 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, } + static si_info_t * si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) @@ -300,17 +311,6 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, bzero((uchar*)sii, sizeof(si_info_t)); - - { - if (NULL == (common_info_alloced = (void *)MALLOC(osh, sizeof(si_common_info_t)))) { - SI_ERROR(("si_doattach: malloc failed! malloced %dbytes\n", MALLOCED(osh))); - return (NULL); - } - bzero((uchar*)(common_info_alloced), sizeof(si_common_info_t)); - } - sii->common_info = (si_common_info_t *)common_info_alloced; - sii->common_info->attach_count++; - savewin = 0; sih->buscoreidx = BADIDX; @@ -320,6 +320,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, sii->osh = osh; + /* find Chipcommon address */ if (bustype == PCI_BUS) { savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); @@ -327,8 +328,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, savewin = SI_ENUM_BASE; OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); cc = (chipcregs_t *)regs; - } else - if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { + } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { cc = (chipcregs_t *)sii->curmap; } else { cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); @@ -358,8 +358,18 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, sih->chip = w & CID_ID_MASK; sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chippkg != BCM4329_289PIN_PKG_ID)) + if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) + >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | + CST4322_SPROM_PRESENT))) { + SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); + return NULL; + } + + if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && + (sih->chippkg != BCM4329_289PIN_PKG_ID)) { sih->chippkg = BCM4329_182PIN_PKG_ID; + } + sih->issim = IS_SIM(sih->chippkg); /* scan for cores */ @@ -369,9 +379,13 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { SI_MSG(("Found chip type AI (0x%08x)\n", w)); /* pass chipc address instead of original core base */ - ai_scan(&sii->pub, (void *)cc, devid); + ai_scan(&sii->pub, (void *)(uintptr)cc, devid); + } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { + SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); + /* pass chipc address instead of original core base */ + ub_scan(&sii->pub, (void *)(uintptr)cc, devid); } else { - SI_ERROR(("Found chip of unkown type (0x%08x)\n", w)); + SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); return NULL; } /* no cores found, bail out */ @@ -383,25 +397,47 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, origidx = SI_CC_IDX; if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { SI_ERROR(("si_doattach: si_buscore_setup failed\n")); - return NULL; + goto exit; } + /* assume current core is CC */ + if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || + CHIPID(sih->chip) == BCM43235_CHIP_ID || + CHIPID(sih->chip) == BCM43238_CHIP_ID) && + (CHIPREV(sii->pub.chiprev) == 0))) { + + if ((cc->chipstatus & CST43236_BP_CLK) != 0) { + uint clkdiv; + clkdiv = R_REG(osh, &cc->clkdiv); + /* otp_clk_div is even number, 120/14 < 9mhz */ + clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); + W_REG(osh, &cc->clkdiv, clkdiv); + SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); + } + OSL_DELAY(10); + } + + pvars = NULL; + + if (sii->pub.ccrev >= 20) { cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); + ASSERT(cc != NULL); W_REG(osh, &cc->gpiopullup, 0); W_REG(osh, &cc->gpiopulldown, 0); si_setcoreidx(sih, origidx); } - /* Skip PMU initialization from the Dongle Host. - * Firmware will take care of it when it comes up. - */ return (sii); + +exit: + + return NULL; } /* may be called with core in reset */ @@ -411,6 +447,7 @@ si_detach(si_t *sih) si_info_t *sii; uint idx; + sii = SI_INFO(sih); if (sii == NULL) @@ -418,16 +455,12 @@ si_detach(si_t *sih) if (BUSTYPE(sih->bustype) == SI_BUS) for (idx = 0; idx < SI_MAXCORES; idx++) - if (sii->common_info->regs[idx]) { - REG_UNMAP(sii->common_info->regs[idx]); - sii->common_info->regs[idx] = NULL; + if (sii->regs[idx]) { + REG_UNMAP(sii->regs[idx]); + sii->regs[idx] = NULL; } - if (1 == sii->common_info->attach_count--) { - MFREE(sii->osh, sii->common_info, sizeof(si_common_info_t)); - common_info_alloced = NULL; - } #if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) if (sii != &ksii) @@ -472,7 +505,7 @@ si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, /* save current core id. when this function called, the current core * must be the core which provides driver functions(il, et, wl, etc.) */ - sii->dev_coreid = sii->common_info->coreid[sii->curidx]; + sii->dev_coreid = sii->coreid[sii->curidx]; } void @@ -488,13 +521,12 @@ uint si_intflag(si_t *sih) { si_info_t *sii = SI_INFO(sih); - if (CHIPTYPE(sih->socitype) == SOCI_SB) { - sbconfig_t *ccsbr = (sbconfig_t *)((uintptr)((ulong) - (sii->common_info->coresba[SI_CC_IDX]) + SBCONFIGOFF)); - return R_REG(sii->osh, &ccsbr->sbflagst); - } else if (CHIPTYPE(sih->socitype) == SOCI_AI) + + if (CHIPTYPE(sih->socitype) == SOCI_SB) + return sb_intflag(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_AI) return R_REG(sii->osh, ((uint32 *)(uintptr) - (sii->common_info->oob_router + OOB_STATUSA))); + (sii->oob_router + OOB_STATUSA))); else { ASSERT(0); return 0; @@ -508,6 +540,8 @@ si_flag(si_t *sih) return sb_flag(sih); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_flag(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_flag(sih); else { ASSERT(0); return 0; @@ -521,6 +555,8 @@ si_setint(si_t *sih, int siflag) sb_setint(sih, siflag); else if (CHIPTYPE(sih->socitype) == SOCI_AI) ai_setint(sih, siflag); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_setint(sih, siflag); else ASSERT(0); } @@ -531,7 +567,7 @@ si_coreid(si_t *sih) si_info_t *sii; sii = SI_INFO(sih); - return sii->common_info->coreid[sii->curidx]; + return sii->coreid[sii->curidx]; } uint @@ -563,7 +599,7 @@ si_coreunit(si_t *sih) /* count the cores of our type */ for (i = 0; i < idx; i++) - if (sii->common_info->coreid[i] == coreid) + if (sii->coreid[i] == coreid) coreunit++; return (coreunit); @@ -576,6 +612,8 @@ si_corevendor(si_t *sih) return sb_corevendor(sih); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_corevendor(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corevendor(sih); else { ASSERT(0); return 0; @@ -595,6 +633,8 @@ si_corerev(si_t *sih) return sb_corerev(sih); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_corerev(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corerev(sih); else { ASSERT(0); return 0; @@ -614,7 +654,7 @@ si_findcoreidx(si_t *sih, uint coreid, uint coreunit) found = 0; for (i = 0; i < sii->numcores; i++) - if (sii->common_info->coreid[i] == coreid) { + if (sii->coreid[i] == coreid) { if (found == coreunit) return (i); found++; @@ -631,7 +671,7 @@ si_corelist(si_t *sih, uint coreid[]) sii = SI_INFO(sih); - bcopy((uchar*)sii->common_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); + bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); return (sii->numcores); } @@ -665,6 +705,8 @@ si_setcore(si_t *sih, uint coreid, uint coreunit) return sb_setcoreidx(sih, idx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_setcoreidx(sih, idx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, idx); else { ASSERT(0); return NULL; @@ -678,6 +720,8 @@ si_setcoreidx(si_t *sih, uint coreidx) return sb_setcoreidx(sih, coreidx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_setcoreidx(sih, coreidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_setcoreidx(sih, coreidx); else { ASSERT(0); return NULL; @@ -685,13 +729,25 @@ si_setcoreidx(si_t *sih, uint coreidx) } /* Turn off interrupt as required by sb_setcore, before switch core */ -void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) +void * +si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) { void *cc; si_info_t *sii; sii = SI_INFO(sih); + if (SI_FAST(sii)) { + /* Overloading the origidx variable to remember the coreid, + * this works because the core ids cannot be confused with + * core indices. + */ + *origidx = coreid; + if (coreid == CC_CORE_ID) + return (void *)CCREGS_FAST(sii); + else if (coreid == sih->buscoretype) + return (void *)PCIEREGS(sii); + } INTR_OFF(sii, *intr_val); *origidx = sii->curidx; cc = si_setcore(sih, coreid, 0); @@ -701,11 +757,14 @@ void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) } /* restore coreidx and restore interrupt */ -void si_restore_core(si_t *sih, uint coreid, uint intr_val) +void +si_restore_core(si_t *sih, uint coreid, uint intr_val) { si_info_t *sii; sii = SI_INFO(sih); + if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) + return; si_setcoreidx(sih, coreid); INTR_RESTORE(sii, intr_val); @@ -718,6 +777,8 @@ si_numaddrspaces(si_t *sih) return sb_numaddrspaces(sih); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_numaddrspaces(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_numaddrspaces(sih); else { ASSERT(0); return 0; @@ -731,6 +792,8 @@ si_addrspace(si_t *sih, uint asidx) return sb_addrspace(sih, asidx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_addrspace(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspace(sih, asidx); else { ASSERT(0); return 0; @@ -744,6 +807,8 @@ si_addrspacesize(si_t *sih, uint asidx) return sb_addrspacesize(sih, asidx); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_addrspacesize(sih, asidx); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_addrspacesize(sih, asidx); else { ASSERT(0); return 0; @@ -757,6 +822,8 @@ si_core_cflags(si_t *sih, uint32 mask, uint32 val) return sb_core_cflags(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_core_cflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_cflags(sih, mask, val); else { ASSERT(0); return 0; @@ -770,6 +837,8 @@ si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) sb_core_cflags_wo(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_AI) ai_core_cflags_wo(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_cflags_wo(sih, mask, val); else ASSERT(0); } @@ -781,6 +850,8 @@ si_core_sflags(si_t *sih, uint32 mask, uint32 val) return sb_core_sflags(sih, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_core_sflags(sih, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_core_sflags(sih, mask, val); else { ASSERT(0); return 0; @@ -794,6 +865,8 @@ si_iscoreup(si_t *sih) return sb_iscoreup(sih); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_iscoreup(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_iscoreup(sih); else { ASSERT(0); return FALSE; @@ -801,12 +874,23 @@ si_iscoreup(si_t *sih) } uint +si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) +{ + /* only for AI back plane chips */ + if (CHIPTYPE(sih->socitype) == SOCI_AI) + return (ai_wrap_reg(sih, offset, mask, val)); + return 0; +} + +uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { if (CHIPTYPE(sih->socitype) == SOCI_SB) return sb_corereg(sih, coreidx, regoff, mask, val); else if (CHIPTYPE(sih->socitype) == SOCI_AI) return ai_corereg(sih, coreidx, regoff, mask, val); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + return ub_corereg(sih, coreidx, regoff, mask, val); else { ASSERT(0); return 0; @@ -820,6 +904,8 @@ si_core_disable(si_t *sih, uint32 bits) sb_core_disable(sih, bits); else if (CHIPTYPE(sih->socitype) == SOCI_AI) ai_core_disable(sih, bits); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_disable(sih, bits); } void @@ -829,13 +915,8 @@ si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) sb_core_reset(sih, bits, resetbits); else if (CHIPTYPE(sih->socitype) == SOCI_AI) ai_core_reset(sih, bits, resetbits); -} - -void -si_core_tofixup(si_t *sih) -{ - if (CHIPTYPE(sih->socitype) == SOCI_SB) - sb_core_tofixup(sih); + else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) + ub_core_reset(sih, bits, resetbits); } /* Run bist on current core. Caller needs to take care of core-specific bist hazards */ @@ -849,7 +930,7 @@ si_corebist(si_t *sih) cflags = si_core_cflags(sih, 0, 0); /* Set bist & fgc */ - si_core_cflags(sih, 0, (SICF_BIST_EN | SICF_FGC)); + si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); /* Wait for bist done */ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); @@ -966,67 +1047,50 @@ si_clock_rate(uint32 pll_type, uint32 n, uint32 m) void si_watchdog(si_t *sih, uint ticks) { + uint nb, maxt; + if (PMUCTL_ENAB(sih)) { + + if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && + (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); + si_setcore(sih, USB20D_CORE_ID, 0); + si_core_disable(sih, 1); + si_setcore(sih, CC_CORE_ID, 0); + } + + nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); + /* The mips compiler uses the sllv instruction, + * so we specially handle the 32-bit case. + */ + if (nb == 32) + maxt = 0xffffffff; + else + maxt = ((1 << nb) - 1); + if (ticks == 1) ticks = 2; + else if (ticks > maxt) + ticks = maxt; + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); } else { - /* instant NMI */ + maxt = (1 << 28) - 1; + if (ticks > maxt) + ticks = maxt; + si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); } } -#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) /* trigger watchdog reset after ms milliseconds */ void si_watchdog_ms(si_t *sih, uint32 ms) { - si_info_t *sii; - - sii = SI_INFO(sih); - si_watchdog(sih, wd_msticks * ms); } -#endif - - - -/* initialize the sdio core */ -void -si_sdio_init(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - - if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) || \ - (sih->buscoretype == SDIOD_CORE_ID)) { - uint idx; - sdpcmd_regs_t *sdpregs; - /* get the current core index */ - idx = sii->curidx; - ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0)); - /* switch to sdio core */ - if (!(sdpregs = (sdpcmd_regs_t *)si_setcore(sih, PCMCIA_CORE_ID, 0))) - 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 " \ - "through SD core %d (%p)\n", - sih->buscorerev, idx, sii->curidx, sdpregs)); - - /* enable backplane error and core interrupts */ - W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT); - W_REG(sii->osh, &sdpregs->sbintmask, (I_SB_SERR | I_SB_RESPERR | (1 << idx))); - - /* switch back to previous core */ - si_setcoreidx(sih, idx); - } - - /* enable interrupts */ - bcmsdh_intr_enable(sii->sdh); - -} /* change logical "focus" to the gpio core for optimized access */ @@ -1115,17 +1179,17 @@ si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) */ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return -1; + return 0xffffffff; } /* make sure only one bit is set */ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return -1; + return 0xffffffff; } /* already reserved */ if (si_gpioreservation & gpio_bitmask) - return -1; + return 0xffffffff; /* set reservation */ si_gpioreservation |= gpio_bitmask; @@ -1150,17 +1214,17 @@ si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) */ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); - return -1; + return 0xffffffff; } /* make sure only one bit is set */ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); - return -1; + return 0xffffffff; } /* already released */ if (!(si_gpioreservation & gpio_bitmask)) - return -1; + return 0xffffffff; /* clear reservation */ si_gpioreservation &= ~gpio_bitmask; @@ -1232,7 +1296,7 @@ si_gpioled(si_t *sih, uint32 mask, uint32 val) sii = SI_INFO(sih); if (sih->ccrev < 16) - return -1; + return 0xffffffff; /* gpio led powersave reg */ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); @@ -1247,7 +1311,7 @@ si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) sii = SI_INFO(sih); if (sih->ccrev < 16) - return -1; + return 0xffffffff; return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); @@ -1261,7 +1325,7 @@ si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) sii = SI_INFO(sih); if (sih->ccrev < 20) - return -1; + return 0xffffffff; offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); @@ -1275,7 +1339,7 @@ si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) sii = SI_INFO(sih); if (sih->ccrev < 11) - return -1; + return 0xffffffff; if (regtype == GPIO_REGEVT) offs = OFFSETOF(chipcregs_t, gpioevent); @@ -1284,7 +1348,7 @@ si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) else if (regtype == GPIO_REGEVT_INTPOL) offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); else - return -1; + return 0xffffffff; return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); } @@ -1355,16 +1419,19 @@ si_gpio_handler_process(si_t *sih) { si_info_t *sii; gpioh_item_t *h; - uint32 status; uint32 level = si_gpioin(sih); + uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); + uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); sii = SI_INFO(sih); for (h = sii->gpioh_head; h != NULL; h = h->next) { if (h->handler) { - status = (h->level ? level : edge); + uint32 status = (h->level ? level : edge) & h->event; + uint32 polarity = (h->level ? levelp : edgep) & h->event; - if (status & h->event) + /* polarity bitval is opposite of status bitval */ + if (status ^ polarity) h->handler(status, h->arg); } } @@ -1380,13 +1447,154 @@ si_gpio_int_enable(si_t *sih, bool enable) sii = SI_INFO(sih); if (sih->ccrev < 11) - return -1; + return 0xffffffff; offs = OFFSETOF(chipcregs_t, intmask); return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); } +/* Return the size of the specified SOCRAM bank */ +static uint +socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 index, uint8 mem_type) +{ + uint banksize, bankinfo; + uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + + ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); + + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); + return banksize; +} + +void +si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect) +{ + si_info_t *sii; + uint origidx; + uint intr_val = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + sii = SI_INFO(sih); + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + if (!set) + *enable = *protect = 0; + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + uint32 bankidx, bankinfo; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); + for (i = 0; i < nb; i++) { + bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + W_REG(sii->osh, ®s->bankidx, bankidx); + bankinfo = R_REG(sii->osh, ®s->bankinfo); + if (set) { + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; + bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; + if (*enable) { + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); + if (*protect) + bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); + } + W_REG(sii->osh, ®s->bankinfo, bankinfo); + } + else if (i == 0) { + if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { + *enable = 1; + if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) + *protect = 1; + } + } + } + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); +} + +bool +si_socdevram_pkg(si_t *sih) +{ + if (si_socdevram_size(sih) > 0) + return TRUE; + else + return FALSE; +} + +uint32 +si_socdevram_size(si_t *sih) +{ + si_info_t *sii; + uint origidx; + uint intr_val = 0; + uint32 memsize = 0; + sbsocramregs_t *regs; + bool wasup; + uint corerev; + + sii = SI_INFO(sih); + + /* Block ints and save current core */ + INTR_OFF(sii, intr_val); + origidx = si_coreidx(sih); + + /* Switch to SOCRAM core */ + if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) + goto done; + + /* Get info for determining size */ + if (!(wasup = si_iscoreup(sih))) + si_core_reset(sih, 0, 0); + + corerev = si_corerev(sih); + if (corerev >= 10) { + uint32 extcinfo; + uint8 nb; + uint8 i; + + extcinfo = R_REG(sii->osh, ®s->extracoreinfo); + nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); + } + + /* Return to previous state and core */ + if (!wasup) + si_core_disable(sih, 0); + si_setcoreidx(sih, origidx); + +done: + INTR_RESTORE(sii, intr_val); + + return memsize; +} + /* Return the RAM size of the SOCRAM core */ uint32 si_socram_size(si_t *sih) @@ -1423,7 +1631,7 @@ si_socram_size(si_t *sih) else if (corerev < 3) { memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; - } else { + } else if ((corerev <= 7) || (corerev == 12)) { uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; uint bsz = (coreinfo & SRCI_SRBSZ_MASK); uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; @@ -1432,6 +1640,11 @@ si_socram_size(si_t *sih) memsize = nb * (1 << (bsz + SR_BSZ_BASE)); if (lss != 0) memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); + } else { + uint8 i; + uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) + memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); } /* Return to previous state and core */ @@ -1478,6 +1691,14 @@ si_btcgpiowar(si_t *sih) INTR_RESTORE(sii, intr_val); } +uint +si_pll_reset(si_t *sih) +{ + uint err = 0; + + return (err); +} + /* check if the device is removed */ bool si_deviceremoved(si_t *sih) @@ -1493,10 +1714,7 @@ si_deviceremoved(si_t *sih) w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32)); if ((w & 0xFFFF) != VENDOR_BROADCOM) return TRUE; - else - return FALSE; - default: - return FALSE; + break; } return FALSE; } diff --git a/src/shared/siutils_priv.h b/src/shared/siutils_priv.h index 6e6df6d..d80246e 100644 --- a/src/shared/siutils_priv.h +++ b/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-2011, 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,19 @@ * 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_priv.h,v 1.3.10.5 2008/08/06 06:28:10 Exp $ + * $Id: siutils_priv.h,v 1.17.4.3 2010-10-25 16:56:56 Exp $ */ #ifndef _siutils_priv_h_ #define _siutils_priv_h_ -/* debug/trace */ #define SI_ERROR(args) #define SI_MSG(args) +/* Define SI_VMSG to printf for verbose debugging, but don't check it in */ +#define SI_VMSG(args) + #define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) typedef uint32 (*si_intrsoff_t)(void *intr_arg); @@ -47,34 +49,19 @@ typedef struct gpioh_item { } gpioh_item_t; /* misc si info needed by some of the routines */ -typedef struct si_common_info { - void *regs[SI_MAXCORES]; /* other regs va */ - void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ - uint coreid[SI_MAXCORES]; /* id of each core */ - uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ - uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ - uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ - uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ - uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ - uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ - void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ - uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ - uint32 oob_router; /* oob router registers for axi */ - uint8 attach_count; -} si_common_info_t; - typedef struct si_info { struct si_pub pub; /* back plane public state (must be first field) */ void *osh; /* osl os handle */ void *sdh; /* bcmsdh handle */ - void *pch; /* PCI/E core handle */ + uint dev_coreid; /* the core provides driver functions */ void *intr_arg; /* interrupt callback function arg */ si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ + void *pch; /* PCI/E core handle */ gpioh_item_t *gpioh_head; /* GPIO event handlers list */ @@ -84,11 +71,24 @@ typedef struct si_info { uint varsz; void *curmap; /* current regs va */ + void *regs[SI_MAXCORES]; /* other regs va */ uint curidx; /* current core index */ uint numcores; /* # discovered cores */ + uint coreid[SI_MAXCORES]; /* id of each core */ + uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ + void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ + uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ + uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ + uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ + void *curwrap; /* current wrapper va */ - si_common_info_t *common_info; /* Common information for all the cores in a chip */ + void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ + uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ + + uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ + uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ + uint32 oob_router; /* oob router registers for axi */ } si_info_t; #define SI_INFO(sih) (si_info_t *)(uintptr)sih @@ -98,7 +98,6 @@ typedef struct si_info { #define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) #define BADCOREADDR 0 #define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) -#define BADIDX (SI_MAXCORES + 1) #define NOREV -1 /* Invalid rev */ #define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ @@ -121,10 +120,10 @@ typedef struct si_info { * after core switching to avoid invalid register accesss inside ISR. */ #define INTR_OFF(si, intr_val) \ - if ((si)->intrsoff_fn && (si)->common_info->coreid[(si)->curidx] == (si)->dev_coreid) { \ + if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } #define INTR_RESTORE(si, intr_val) \ - if ((si)->intrsrestore_fn && (si)->common_info->coreid[(si)->curidx] == (si)->dev_coreid) {\ + if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } /* dynamic clock control defines */ @@ -140,7 +139,8 @@ typedef struct si_info { #define PCI_FORCEHT(si) \ (((PCIE(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ - ((PCI(si) || PCIE(si)) && (si->pub.chip == BCM4321_CHIP_ID))) + ((PCI(si) || PCIE(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ + (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID))) /* GPIO Based LED powersave defines */ #define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ @@ -153,6 +153,7 @@ typedef struct si_info { /* Silicon Backplane externs */ extern void sb_scan(si_t *sih, void *regs, uint devid); extern uint sb_coreid(si_t *sih); +extern uint sb_intflag(si_t *sih); extern uint sb_flag(si_t *sih); extern void sb_setint(si_t *sih, int siflag); extern uint sb_corevendor(si_t *sih); @@ -167,7 +168,6 @@ extern void sb_commit(si_t *sih); extern uint32 sb_base(uint32 admatch); extern uint32 sb_size(uint32 admatch); extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -extern void sb_core_tofixup(si_t *sih); extern void sb_core_disable(si_t *sih, uint32 bits); extern uint32 sb_addrspace(si_t *sih, uint asidx); extern uint32 sb_addrspacesize(si_t *sih, uint asidx); @@ -175,6 +175,7 @@ extern int sb_numaddrspaces(si_t *sih); extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); +extern bool sb_taclear(si_t *sih, bool details); /* Wake-on-wireless-LAN (WOWL) */ @@ -207,6 +208,28 @@ extern void ai_core_disable(si_t *sih, uint32 bits); extern int ai_numaddrspaces(si_t *sih); extern uint32 ai_addrspace(si_t *sih, uint asidx); extern uint32 ai_addrspacesize(si_t *sih, uint asidx); - +extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); + + + +#define ub_scan(a, b, c) do {} while (0) +#define ub_flag(a) (0) +#define ub_setint(a, b) do {} while (0) +#define ub_coreidx(a) (0) +#define ub_corevendor(a) (0) +#define ub_corerev(a) (0) +#define ub_iscoreup(a) (0) +#define ub_setcoreidx(a, b) (0) +#define ub_core_cflags(a, b, c) (0) +#define ub_core_cflags_wo(a, b, c) do {} while (0) +#define ub_core_sflags(a, b, c) (0) +#define ub_corereg(a, b, c, d, e) (0) +#define ub_core_reset(a, b, c) do {} while (0) +#define ub_core_disable(a, b) do {} while (0) +#define ub_numaddrspaces(a) (0) +#define ub_addrspace(a, b) (0) +#define ub_addrspacesize(a, b) (0) +#define ub_view(a, b) do {} while (0) +#define ub_dumpregs(a, b) do {} while (0) #endif /* _siutils_priv_h_ */ diff --git a/src/wl/exe/wlu_remote.h b/src/wl/exe/wlu_remote.h new file mode 100644 index 0000000..c6b1513 --- /dev/null +++ b/src/wl/exe/wlu_remote.h @@ -0,0 +1,236 @@ +/* + * OS independent remote wl declarations + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: wlu_remote.h,v 1.18.2.2 2010-12-22 18:59:03 Exp $ + */ +#ifndef _wlu_remote_h +#define _wlu_remote_h +#include <wlioctl.h> +/* Remote wl declararions */ +#define NO_REMOTE 0 +#define REMOTE_SERIAL 1 +#define REMOTE_SOCKET 2 +#define REMOTE_WIFI 3 +#define REMOTE_DONGLE 4 +#define SHELL_CMD -1 /* Invalid cmd id for shell */ +#define ASD_CMD -2 /* Cmd id for ASD command */ +#define SERVER_RESPONSE_MAX_BUF_LEN 8192 +#define SHELL_RESP_SIZE 1024 +#define CTRLC_PACKET 0xDEADBEAF +#define CTRLC_FLAG -4 +#define VISTA_CMD -3 /* cmd id for remote vista */ + +/* For cross OS support */ +#define LINUX_OS 1 +#define WIN32_OS 2 +#define MAC_OSX 3 +#define BACKLOG 4 +#define WINVISTA_OS 5 +#define INDONGLE 6 + +/* Used in cdc_ioctl_t.flags field */ +#define REMOTE_SET_IOCTL 1 +#define REMOTE_GET_IOCTL 2 +#define REMOTE_REPLY 4 +#define REMOTE_SHELL_CMD 8 +#define REMOTE_FINDSERVER_IOCTL 16 /* Find remote server */ +#define REMOTE_ASD_CMD 32 /* ASD integration */ +#define RDHD_SET_IOCTL 64 +#define RDHD_GET_IOCTL 128 +#define REMOTE_VISTA_CMD 256 /* for remote vista specific commands */ +#define RWL_WIFI_DEFAULT_TYPE 0x00 +#define RWL_WIFI_DEFAULT_SUBTYPE 0x00 +#define RWL_ACTION_FRAME_DATA_SIZE 1024 /* fixed size for the wifi frame data */ +#define RWL_WIFI_CDC_HEADER_OFFSET 0 +#define RWL_WIFI_FRAG_DATA_SIZE 960 /* max size of the frag data */ +#define RWL_DEFAULT_WIFI_FRAG_COUNT 127 /* maximum fragment count */ +#define RWL_WIFI_RETRY 5 /* CMD retry count for wifi */ +#define RWL_WIFI_RX_RETRY 20 /* WIFI response rerty count */ +#define RWL_WIFI_SEND 5 /* WIFI frame sent count */ +#define RWL_WIFI_RETRY_DELAY 1000 /* wifi specific retry delay */ +#define RWL_WIFI_SEND_DELAY 100 /* delay between two frames */ +#define RWL_WIFI_RX_DELAY 250 /* wait between send and receive */ +#define RWL_WIFI_RX_SHELL_DELAY 1000 /* delay added for shell cmd response read */ +#define RWL_CHANNEL_RX_SCAN_DELAY 10 /* Delay between findserver rx calls */ +#define RWL_CHANNEL_SCAN_WAIT 250 /* Sleep time in between the channel scans */ +#define RWL_WIFI_BUF_LEN 64 +#define RWL_WIFI_SHELL_CMD 1 +#define RWL_WIFI_WL_CMD 0 +#define RWL_WIFI_FIND_SER_CMD "findserver" +#define RWL_WIFI_ACTION_CMD "wifiaction" +#define RWL_WIFI_GET_ACTION_CMD "rwlwifivsaction" +#define RWL_DONGLE_SET_CMD "dongleset" +#define DATA_FRAME_LEN 960 +/* wl & shell cmd work fine for 960 (512+256+128+64) */ + + +/* + * Information about the action frame data fields in the + * dot11_action_wifi_vendor_specific + * cdc struct (1 to 16. This does not include status flag. Since this + * is not directly visible to the driver code we cant use sizeof struct + * cdc_ioctl_t. Hence Ref MAC address offset starts from byte 17. + * REF MAC ADDR (6 bytes (MAC Address len) from byte 17 to 22) + * DUT MAC ADDR (6 bytes after the REF MAC Address byte 23 to 28) + * unused (byte 29 to 49) + * REF/Client Channel offset (50) + * DUT/Server channel offset (51) + * --------------------------------------------------------------------------------------- + * cdc struct|REF MAC ADDR|DUT_MAC_ADDR|un used|REF Channel|DUT channel|Action frame Data| + * 1---------17-----------23-------------------50----------51----------52----------------1040 + * REF MAC addr after CDC struct without status flag (status flag not used by wifi) + */ +#define RWL_ACTION_WIFI_CATEGORY 127 /* Vendor Specific category value for wifi */ +#define RWL_REF_MAC_ADDRESS_OFFSET 17 +#define RWL_DUT_MAC_ADDRESS_OFFSET 23 +#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50 +#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51 + +#define SUCCESS 1 +#define FAIL -1 +#define NO_PACKET -2 +#define SERIAL_PORT_ERR -3 + +#define DEFAULT_SERVER_PORT 8000 + +#define WL_MAX_BUF_LEN (127 * 1024) +#define MAX_VISTA_ARGC 10 +#define HOST_TO_NETWORK TRUE +#define NETWORK_TO_HOST FALSE + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +/* We don't want the server to allocate bigger buffers for some of the commands + * like scanresults. Server can still allocate 8K memory and send the response + * in fragments. This is used in case of Get commands only. + */ +#define SERVER_RESPONSE_MAX_BUF_LEN 8192 +/* Used to set the cmds for wifi specific init */ +typedef struct remote_wifi_cmds { + uint32 cmd; /* common ioctl definition */ + char *data; /* max size of the data length */ + int value; +} remote_wifi_cmds_t; + +/* Added for debug utility support */ +#define ERR stderr +#define OUTPUT stdout + +#define DEBUG_DEFAULT 0x0001 +#define DEBUG_ERR 0x0001 +#define DEBUG_INFO 0x0002 +#define DEBUG_DBG 0x0004 + +#define DPRINT_ERR if (defined_debug & DEBUG_ERR) \ + fprintf +#define DPRINT_INFO if (defined_debug & DEBUG_INFO) \ + fprintf +#define DPRINT_DBG if (defined_debug & DEBUG_DBG) \ + fprintf +extern unsigned short defined_debug; +#ifdef WIN32 +#define IPV4_ADDR_LEN 4 +/* IPV4 packet formats */ +struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} PACKED; +/* Function defined in wlu.c for client and wlu_server_ce.c for server */ +extern int wl_atoip(const char *a, struct ipv4_addr *n); +#endif +/* Function defined to do host to network and network to host conversions */ +void rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network); + +/* Macros to access remote type */ +extern int remote_type; +#define rwl_get_remote_type() (remote_type) +#define rwl_set_remote_type(type) (remote_type = type) + +/* Macros to access server IP and port globals */ +extern char *g_rwl_servIP; +#define rwl_get_server_ip() (g_rwl_servIP) +#define rwl_set_server_ip(ip) (g_rwl_servIP = ip) +extern unsigned short g_rwl_servport; +#define rwl_get_server_port() (g_rwl_servport) +#define rwl_set_server_port(port) (g_rwl_servport = port) + +extern int rwl_connectsocket(int SocketDes, struct sockaddr* SerAddr, int SizeOfAddr); +extern int rwl_send_to_streamsocket(int SocketDes, const char* SendBuff, int data_size, int Flag); +extern int rwl_receive_from_streamsocket(int SocketDes, char* RecvBuff, int data_size, int Flag); +extern int rwl_read_serial_port(void* hndle, char* read_buf, uint data_size, uint *numread); +extern int rwl_write_serial_port(void* hndle, char* write_buf, unsigned long size, +unsigned long *numwritten); +extern void rwl_sleep(int delay); +extern void* rwl_open_transport(int remote_type, char *port, int ReadTotalTimeout, int debug); +extern int rwl_close_transport(int remote_type, void * handle); +extern int rwl_poll_serial_buffer(void *hndle); +extern int rwl_serial_handle_timeout(void); +extern void rwl_sync_delay(uint noframes); +extern int rwl_init_server_socket_setup(int argc, char** argv, uint remote_type); + +extern int rwl_GetifAddr(char *ifname, struct sockaddr_in* sa); +extern int rwl_acceptconnection(int SocketDes, struct sockaddr *ClientAddr, int *SizeOfAddr); +extern int set_interface(void *wl, char *intf_name); +/* Linux specific function in wlu_pipe_linux.c */ +extern int rwl_get_if_addr(char *ifname, struct sockaddr_in *sa); + +/* Win32 specific function wlu_pipe_win32.c */ +extern int rwl_init_ws2_32dll(void); +extern int rwl_terminate_ws2_32dll(void); + +/* Function definitions for wlu_client_shared.c and wlu_server_shared.c */ +extern int rwl_var_getbuf(void *wl, const char *iovar, void *param, int param_len, void **bufptr); +extern int rwl_var_setbuf(void *wl, const char *iovar, void *param, int param_len); +extern int rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len); + +/* Function definitions for wlu_ndis.c/wlu_linux.c and wlu_server_ce.c/wlu_server_linux.c */ +extern int wl_get(void *wl, int cmd, void *buf, int len); +extern int wl_set(void *wl, int cmd, void *buf, int len); +#ifdef RWLASD +typedef unsigned char BYTE; +extern void wfa_dut_init(BYTE **tBuf, BYTE **rBuf, BYTE **paBuf, BYTE **cBuf, struct timeval **); +extern int remote_asd_exec(unsigned char* command, int* cmd_len); +void wfa_dut_deinit(void); +#endif +extern int get_ctrlc_header(void *wl); +extern int remote_tx_response(void *wl, void *buf_ptr, int cmd); +extern rem_ioctl_t *g_rem_ptr; +extern int g_rwl_hndle; +/* Variable to indiate if the server child has completed execution */ +extern volatile sig_atomic_t g_sig_chld; + +#ifndef WIN32 +#ifdef TARGETENV_android +/* + * Separate paths are defined for Android and Linux machines + * / filesystem on Android is read only memory + */ +#define SH_PATH "/data/busybox/sh" +#define SHELL_RESP_PATH "/data/local/RWL/" /* Default path for storing files for shell response */ +#define TEMPLATE "/data/local/RWL/SyncXXXXXX" +#else +#define SHELL_RESP_PATH "/tmp/RWL/" /* Default path for storing files for shell response */ +#define TEMPLATE "/tmp/RWL/SyncXXXXXX" +#define SH_PATH "/bin/sh" +#endif +#endif /* !WIN32 */ +#endif /* _wlu_remote_h */ diff --git a/src/wl/sys/uamp_api.h b/src/wl/sys/uamp_api.h new file mode 100644 index 0000000..c51c68c --- /dev/null +++ b/src/wl/sys/uamp_api.h @@ -0,0 +1,176 @@ +/* + * Name: uamp_api.h + * + * Description: Universal AMP API + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: uamp_api.h,v 1.2.8.1 2011-02-05 00:16:14 Exp $ + * + */ +#ifndef UAMP_API_H +#define UAMP_API_H + + +#include "typedefs.h" + + +/***************************************************************************** +** Constant and Type Definitions +****************************************************************************** +*/ + +#define BT_API + +/* Types. */ +typedef bool BOOLEAN; +typedef uint8 UINT8; +typedef uint16 UINT16; + + +/* UAMP identifiers */ +#define UAMP_ID_1 1 +#define UAMP_ID_2 2 +typedef UINT8 tUAMP_ID; + +/* UAMP event ids (used by UAMP_CBACK) */ +#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ +#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ +#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ +typedef UINT8 tUAMP_EVT; + + +/* UAMP Channels */ +#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ +#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ +#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ +typedef UINT8 tUAMP_CH; + +/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ +typedef union { + tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ +} tUAMP_EVT_DATA; + + +/***************************************************************************** +** +** Function: UAMP_CBACK +** +** Description: Callback for events. Register callback using UAMP_Init. +** +** Parameters amp_id: AMP device identifier that generated the event +** amp_evt: event id +** p_amp_evt_data: pointer to event-specific data +** +****************************************************************************** +*/ +typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); + +/***************************************************************************** +** external function declarations +****************************************************************************** +*/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** +** Function: UAMP_Init +** +** Description: Initialize UAMP driver +** +** Parameters p_cback: Callback function for UAMP event notification +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); + + +/***************************************************************************** +** +** Function: UAMP_Open +** +** Description: Open connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. This value +** will be included in AMP messages sent to the +** BTU task, to identify source of the message +** +****************************************************************************** +*/ +BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); + +/***************************************************************************** +** +** Function: UAMP_Close +** +** Description: Close connection to local AMP device. +** +** Parameters app_id: Application specific AMP identifer. +** +****************************************************************************** +*/ +BT_API void UAMP_Close(tUAMP_ID amp_id); + + +/***************************************************************************** +** +** Function: UAMP_Write +** +** Description: Send buffer to AMP device. Frees GKI buffer when done. +** +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer to write +** num_bytes: number of bytes to write +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD +** +** Returns: number of bytes written +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); + +/***************************************************************************** +** +** Function: UAMP_Read +** +** Description: Read incoming data from AMP. Call after receiving a +** UAMP_EVT_RX_READY callback event. +** +** Parameters: app_id: AMP identifer. +** p_buf: pointer to buffer for holding incoming AMP data +** buf_size: size of p_buf +** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT +** +** Returns: number of bytes read +** +****************************************************************************** +*/ +BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); + +#ifdef __cplusplus +} +#endif + +#endif /* UAMP_API_H */ diff --git a/src/wl/sys/uamp_linux.c b/src/wl/sys/uamp_linux.c new file mode 100644 index 0000000..994aa30 --- /dev/null +++ b/src/wl/sys/uamp_linux.c @@ -0,0 +1,1258 @@ +/* + * Name: uamp_linux.c + * + * Description: Universal AMP API + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: uamp_linux.c,v 1.2.2.1 2011-02-05 00:16:14 Exp $ + * + */ + +/* ---- Include Files ---------------------------------------------------- */ + +#include "typedefs.h" +#include "bcmutils.h" +#include "bcmendian.h" +#include "uamp_api.h" +#include "wlioctl.h" +#include "dhdioctl.h" +#include "proto/bt_amp_hci.h" +#include "proto/bcmevent.h" +#include "proto/802.11_bta.h" + +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <linux/if_packet.h> +#include <pthread.h> + +#include <linux/if_ether.h> +#include <mqueue.h> + +#include <linux/sockios.h> +#include <linux/ethtool.h> + + +/* ---- Public Variables ------------------------------------------------- */ +/* ---- Private Constants and Types -------------------------------------- */ + +#define UAMP_DEBUG 1 + +#define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */ + +#define UAMP_EVT_Q_STR "/uamp_evt_q" +#define UAMP_PKT_RX_Q_STR "/uamp_pkt_rx_q" + +#if UAMP_DEBUG + #define UAMP_PRINT(a) printf a + #define UAMP_TRACE(a) printf a + #define UAMP_ERROR(a) printf a +#else + #define UAMP_PRINT(a) printf a + #define UAMP_TRACE(a) + #define UAMP_ERROR(a) printf a +#endif + +#if ((BRCM_BLUETOOTH_HOST == 1) && (UAMP_IS_GKI_AWARE == 1)) +#include "gki.h" +#define UAMP_ALLOC(a) GKI_getbuf(a+sizeof(BT_HDR)) +#define UAMP_FREE(a) GKI_freebuf(a) +#else +#define UAMP_ALLOC(a) malloc(a) +#define UAMP_FREE(a) free(a) +#endif /* BRCM_BLUETOOTH_HOST && UAMP_IS_GKI_AWARE */ + +#define GET_UAMP_FROM_ID(id) (((id) == 0) ? &g_uamp_mgr.uamp : NULL) + +#define MAX_IOVAR_LEN 2096 + + +/* State associated with a single universal AMP. */ +typedef struct UAMP_STATE +{ + /* Unique universal AMP identifier. */ + tUAMP_ID id; + + /* Event/data queues. */ + mqd_t evt_q; + mqd_t pkt_rx_q; + + /* Event file descriptors. */ + int evt_fd; + int evt_fd_pipe[2]; + + + /* Packet rx descriptors. */ + int pkt_rx_fd; + int pkt_rx_fd_pipe[2]; + + /* Storage buffers for recieved events and packets. */ + uint32 event_data[WLC_IOCTL_SMLEN/4]; + uint32 pkt_data[MAX_IOVAR_LEN/4]; + +} UAMP_STATE; + + +/* State associated with collection of univerisal AMPs. */ +typedef struct UAMP_MGR +{ + /* Event/data callback. */ + tUAMP_CBACK callback; + + /* WLAN interface. */ + struct ifreq ifr; + + /* UAMP state. Only support a single AMP currently. */ + UAMP_STATE uamp; + +} UAMP_MGR; + + +/* ---- Private Variables ------------------------------------------------ */ + +static UAMP_MGR g_uamp_mgr; + + +/* ---- Private Function Prototypes -------------------------------------- */ + +static void usage(void); +static int uamp_accept_test(void); +static int uamp_create_test(void); +static UINT16 uamp_write_cmd(uint16 opcode, uint8 *params, uint8 len, + amp_hci_cmd_t *cmd, unsigned int max_len); +static UINT16 uamp_write_data(uint16 handle, uint8 *data, uint8 len, + amp_hci_ACL_data_t *pkt, unsigned int max_len); + +static int ioctl_get(int cmd, void *buf, int len); +static int ioctl_set(int cmd, void *buf, int len); +static int iovar_set(const char *iovar, void *param, int paramlen); +static int iovar_setbuf(const char *iovar, void *param, int paramlen, void *bufptr, + int buflen); +static int iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, + uint buflen, int *perr); +static int wl_ioctl(int cmd, void *buf, int len, bool set); +static void wl_get_interface_name(struct ifreq *ifr); +static int wl_get_dev_type(char *name, void *buf, int len); +static void syserr(char *s); + +static int init_event_rx(UAMP_STATE *uamp); +static void deinit_event_rx(UAMP_STATE *uamp); +static void* event_thread(void *param); +static void handle_event(UAMP_STATE *uamp); + +static int init_pkt_rx(UAMP_STATE *uamp); +static void deinit_pkt_rx(UAMP_STATE *uamp); +static void* packet_rx_thread(void *param); +static void handle_rx_pkt(UAMP_STATE *uamp); + + +#if (BRCM_BLUETOOTH_HOST == 1) +#if (UAMP_IS_GKI_AWARE == 1) +void wl_event_gki_callback(wl_event_msg_t* event, void* event_data); +int wl_btamp_rx_gki_pkt_callback(wl_drv_netif_pkt pkt, unsigned int len); +#endif /* UAMP_IS_GKI_AWARE */ +static void *uamp_get_acl_buf(unsigned int len); +void *hcisu_amp_get_acl_buf(int len); /* Get GKI buffer from ACL pool */ +void hcisu_handle_amp_data_buf(void *pkt, unsigned int len); /* Send GKI buffer to BTU task */ +void hcisu_handle_amp_evt_buf(void* evt, unsigned int len); +int wl_is_drv_init_done(void); +#endif /* BRCM_BLUETOOTH_HOST */ + +/* ---- Functions -------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ +BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback) +{ + memset(&g_uamp_mgr, 0, sizeof(g_uamp_mgr)); + g_uamp_mgr.callback = p_cback; + + wl_get_interface_name(&g_uamp_mgr.ifr); + + return (TRUE); +} + + +/* ------------------------------------------------------------------------- */ +BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id) +{ + UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id); + +#if (BRCM_BLUETOOTH_HOST == 1) + if (!wl_is_drv_init_done()) { + UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__)); + return FALSE; + } +#endif /* BRCM_BLUETOOTH_HOST */ + + /* Setup event receive. */ + if ((init_event_rx(uamp)) < 0) { + return (FALSE); + } + + /* Setup packet receive. */ + if ((init_pkt_rx(uamp)) < 0) { + return (FALSE); + } + + return (TRUE); +} + + +/* ------------------------------------------------------------------------- */ +BT_API void UAMP_Close(tUAMP_ID amp_id) +{ + UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id); + +#if (BRCM_BLUETOOTH_HOST == 1) + if (!wl_is_drv_init_done()) { + UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__)); + return; + } +#endif /* BRCM_BLUETOOTH_HOST */ + + /* Cleanup packet and event receive. */ + deinit_pkt_rx(uamp); + deinit_event_rx(uamp); +} + +/* ------------------------------------------------------------------------- */ +BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel) +{ + int ret = -1; + UINT16 num_bytes_written = num_bytes; + + UNUSED_PARAMETER(amp_id); + +#if (BRCM_BLUETOOTH_HOST == 1) + if (!wl_is_drv_init_done()) { + UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__)); + return (0); + } +#endif /* BRCM_BLUETOOTH_HOST */ + + if (channel == UAMP_CH_HCI_CMD) { + ret = iovar_set("HCI_cmd", p_buf, num_bytes); + } + else if (channel == UAMP_CH_HCI_DATA) { + ret = iovar_set("HCI_ACL_data", p_buf, num_bytes); + } + + if (ret != 0) { + num_bytes_written = 0; + UAMP_ERROR(("UAMP_Write error: %i ( 0=success )\n", ret)); + } + + return (num_bytes_written); +} + + +/* ------------------------------------------------------------------------- */ +BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel) +{ + UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id); + mqd_t num_bytes; + unsigned int msg_prio; + +#if (BRCM_BLUETOOTH_HOST == 1) + if (!wl_is_drv_init_done()) { + UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__)); + return (0); + } +#endif /* BRCM_BLUETOOTH_HOST */ + + + if (channel == UAMP_CH_HCI_EVT) { + /* Dequeue event. */ + num_bytes = mq_receive(uamp->evt_q, (char *)p_buf, buf_size, &msg_prio); + if (num_bytes == -1) { + UAMP_ERROR(("%s: Event queue receive error!\n", __FUNCTION__)); + return (0); + } + + return (num_bytes); + } + else if (channel == UAMP_CH_HCI_DATA) { + /* Dequeue rx packet. */ + num_bytes = mq_receive(uamp->pkt_rx_q, (char *)p_buf, buf_size, &msg_prio); + if (num_bytes == -1) { + UAMP_ERROR(("%s: Pkt queue receive error!\n", __FUNCTION__)); + return (0); + } + + return (num_bytes); + } + + return (0); +} + + +/* + * Get IOCTL given the parameter buffer. + */ +static int +ioctl_get(int cmd, void *buf, int len) +{ + return wl_ioctl(cmd, buf, len, FALSE); +} + + +/* + * Set IOCTL given the parameter buffer. + */ +static int +ioctl_set(int cmd, void *buf, int len) +{ + return wl_ioctl(cmd, buf, len, TRUE); +} + + +/* + * Set named iovar given the parameter buffer. + */ +static int +iovar_set(const char *iovar, void *param, int paramlen) +{ + static char smbuf[MAX_IOVAR_LEN]; + + memset(smbuf, 0, sizeof(smbuf)); + + return iovar_setbuf(iovar, param, paramlen, smbuf, sizeof(smbuf)); +} + +/* + * Set named iovar providing both parameter and i/o buffers. + */ +static int +iovar_setbuf(const char *iovar, + void *param, int paramlen, void *bufptr, int buflen) +{ + int err; + int iolen; + + iolen = iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err); + if (err) + return err; + + return ioctl_set(DHD_SET_VAR, bufptr, iolen); +} + + +/* + * Format an iovar buffer. + */ +static int +iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, uint buflen, int *perr) +{ + int iovar_len; + + iovar_len = strlen(name) + 1; + + /* check for overflow */ + if ((iovar_len + datalen) > buflen) { + *perr = -1; + return 0; + } + + /* copy data to the buffer past the end of the iovar name string */ + if (datalen > 0) + memmove(&iovar_buf[iovar_len], data, datalen); + + /* copy the name to the beginning of the buffer */ + strcpy(iovar_buf, name); + + *perr = 0; + return (iovar_len + datalen); +} + + +/* + * Send IOCTL to WLAN driver. + */ +static int +wl_ioctl(int cmd, void *buf, int len, bool set) +{ + struct ifreq ifr; + dhd_ioctl_t ioc; + int ret = 0; + int s; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, g_uamp_mgr.ifr.ifr_name, sizeof(ifr.ifr_name)); + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ret = -1; + return ret; + } + + /* do it */ + ioc.cmd = cmd; + ioc.buf = buf; + ioc.len = len; + ioc.set = set; + ioc.driver = DHD_IOCTL_MAGIC; + ifr.ifr_data = (caddr_t) &ioc; + if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) { + ret = -1; + } + + /* cleanup */ + close(s); + return ret; +} + + +static int +wl_get_dev_type(char *name, void *buf, int len) +{ + int s; + int ret; + struct ifreq ifr; + struct ethtool_drvinfo info; + + /* open socket to kernel */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + syserr("socket"); + + /* get device type */ + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t)&info; + strncpy(ifr.ifr_name, name, IFNAMSIZ); + if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) { + + /* print a good diagnostic if not superuser */ + if (errno == EPERM) + syserr("wl_get_dev_type"); + + *(char *)buf = '\0'; + } else { + strncpy(buf, info.driver, len); + } + + close(s); + return ret; +} + + +static void +wl_get_interface_name(struct ifreq *ifr) +{ + char proc_net_dev[] = "/proc/net/dev"; + FILE *fp; + char buf[1000], *c, *name; + char dev_type[DEV_TYPE_LEN]; + int ret = -1; + + ifr->ifr_name[0] = '\0'; + + if (!(fp = fopen(proc_net_dev, "r"))) + return; + + /* eat first two lines */ + if (!fgets(buf, sizeof(buf), fp) || + !fgets(buf, sizeof(buf), fp)) { + fclose(fp); + return; + } + + while (fgets(buf, sizeof(buf), fp)) { + c = buf; + while (isspace(*c)) + c++; + if (!(name = strsep(&c, ":"))) + continue; + strncpy(ifr->ifr_name, name, IFNAMSIZ); + if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 && + (!strncmp(dev_type, "wl", 2) || !strncmp(dev_type, "dhd", 3))) + { + ret = 0; + break; + } + ifr->ifr_name[0] = '\0'; + } + + fclose(fp); +} + + +static void +syserr(char *s) +{ + fprintf(stderr, "uamp_linux:"); + perror(s); + exit(errno); +} + + +#if (BRCM_BLUETOOTH_HOST == 1) +static void *uamp_get_acl_buf(unsigned int len) +{ + return (hcisu_amp_get_acl_buf(len)); +} +#endif /* BRCM_BLUETOOTH_HOST */ + + +/* + * Setup packet receive. + */ +static int +init_pkt_rx(UAMP_STATE *uamp) +{ + struct ifreq ifr; + int fd = -1; + struct sockaddr_ll local; + int err; + int fd_pipe[2] = {-1, -1}; + pthread_t h; + + + memset(&ifr, 0, sizeof(ifr)); + wl_get_interface_name(&ifr); + + /* Create and bind socket to receive packets. */ + fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_802_2)); + if (fd < 0) { + UAMP_ERROR(("%s: Cannot open socket", __FUNCTION__)); + return (-1); + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + UAMP_ERROR(("%s: Cannot get index %d\n", __FUNCTION__, err)); + close(fd); + return (-1); + } + + memset(&local, 0, sizeof(local)); + local.sll_family = PF_PACKET; + local.sll_protocol = htons(ETH_P_802_2); + local.sll_ifindex = ifr.ifr_ifindex; + + if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) { + UAMP_ERROR(("%s: Cannot bind socket", __FUNCTION__)); + close(fd); + return (-1); + } + + + /* Create pipe used to terminate receive packet thread. */ + if (pipe(fd_pipe) != 0) { + UAMP_ERROR(("%s: pipe failed\n", __FUNCTION__)); + goto cleanup; + } + + /* Save in instance memory. */ + uamp->pkt_rx_fd = fd; + uamp->pkt_rx_fd_pipe[0] = fd_pipe[0]; + uamp->pkt_rx_fd_pipe[1] = fd_pipe[1]; + + + /* Create message queue for received packets. */ + + uamp->pkt_rx_q = mq_open(UAMP_PKT_RX_Q_STR, O_RDWR | O_CREAT, 0666, NULL); + + + + /* Spawn packet handling thread. */ + pthread_create(&h, NULL, packet_rx_thread, uamp); + + return (fd); + +cleanup: + if (-1 != fd) close(fd); + if (-1 != fd_pipe[0]) close(fd_pipe[0]); + if (-1 != fd_pipe[1]) close(fd_pipe[1]); + return (-1); +} + + +/* + * Cleanup packet receive. + */ +static void +deinit_pkt_rx(UAMP_STATE *uamp) +{ + /* Cleanup the message queue. */ + mq_close(uamp->pkt_rx_q); + mq_unlink(UAMP_PKT_RX_Q_STR); + + /* Kill the receive thread. */ + write(uamp->pkt_rx_fd_pipe[1], NULL, 0); + close(uamp->pkt_rx_fd_pipe[1]); +} + + +/* + * Packet receive thread. + */ +static void* +packet_rx_thread(void *param) +{ + UAMP_STATE *uamp = (UAMP_STATE *) param; + + UAMP_PRINT(("Start packet rx wait loop\n")); + + while (1) { + fd_set rfds; /* fds for select */ + int last_fd; + int ret; + + FD_ZERO(&rfds); + FD_SET(uamp->pkt_rx_fd_pipe[0], &rfds); + FD_SET(uamp->pkt_rx_fd, &rfds); + last_fd = MAX(uamp->pkt_rx_fd_pipe[0], uamp->pkt_rx_fd); + + /* Wait on stop pipe or rx packet socket */ + ret = select(last_fd+1, &rfds, NULL, NULL, NULL); + + /* Error processing */ + if (0 > ret) { + UAMP_ERROR(("%s: Unhandled signal on pkt rx socket\n", __FUNCTION__)); + break; + } + + /* Stop processing */ + if (FD_ISSET(uamp->pkt_rx_fd_pipe[0], &rfds)) { + UAMP_PRINT(("%s: stop rcvd on dispatcher pipe\n", __FUNCTION__)); + break; + } + + /* Packet processing */ + if (FD_ISSET(uamp->pkt_rx_fd, &rfds)) { + handle_rx_pkt(uamp); + } + + } /* end-while(1) */ + + UAMP_PRINT(("%s: End packet rx wait loop\n", __FUNCTION__)); + + close(uamp->pkt_rx_fd); + close(uamp->pkt_rx_fd_pipe[0]); + + UAMP_TRACE(("Exit %s\n", __FUNCTION__)); + return (NULL); +} + +/* + * Process received packet. + */ +static void +handle_rx_pkt(UAMP_STATE *uamp) +{ + int bytes; + struct dot11_llc_snap_header *lsh; + amp_hci_ACL_data_t *acl_data; + + /* Read packet. */ + bytes = recv(uamp->pkt_rx_fd, uamp->pkt_data, sizeof(uamp->pkt_data), MSG_DONTWAIT); + + /* Error handling. */ + if (bytes < 0) { + if (errno != EINTR && errno != EAGAIN) { + UAMP_ERROR(("%s: Error reading packet rx socket: %s\n", + __FUNCTION__, strerror(errno))); + return; + } + } + + if (bytes == 0) { + UAMP_ERROR(("%s: EOF on packet rx socket", __FUNCTION__)); + return; + } + + + /* Verify that this is an HCI data packet. */ + lsh = (struct dot11_llc_snap_header *)uamp->pkt_data; + if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) != 0 || + ntoh16(lsh->type) != BTA_PROT_L2CAP) { + /* Not HCI data. */ + return; + } + + + UAMP_TRACE(("%s: received packet!\n", __FUNCTION__)); + + acl_data = (amp_hci_ACL_data_t *) &lsh[1]; + bytes -= DOT11_LLC_SNAP_HDR_LEN; + +#if (BRCM_BLUETOOTH_HOST == 1) + hcisu_handle_amp_data_buf(acl_data, bytes); +#else + { + tUAMP_EVT_DATA uamp_evt_data; +#if (UAMP_DEBUG == 1) + /* Debug - dump rx packet data. */ + { + int i; + uint8 *data = acl_data->data; + UAMP_TRACE(("data(%d): ", bytes)); + for (i = 0; i < bytes; i++) { + UAMP_TRACE(("0x%x ", data[i])); + } + UAMP_TRACE(("\n")); + } +#endif /* UAMP_DEBUG */ + + /* Post packet to queue. Stack will de-queue it with call to UAMP_Read(). */ + if (mq_send(uamp->pkt_rx_q, (const char *)acl_data, bytes, 0) != 0) { + /* Unable to queue packet */ + UAMP_ERROR(("%s: Unable to queue rx packet data!\n", __FUNCTION__)); + return; + } + + + /* Inform application stack of received packet. */ + memset(&uamp_evt_data, 0, sizeof(uamp_evt_data)); + uamp_evt_data.channel = UAMP_CH_HCI_DATA; + g_uamp_mgr.callback(0, UAMP_EVT_RX_READY, &uamp_evt_data); + } +#endif /* BRCM_BLUETOOTH_HOST */ +} + + +/* + * Setup event receive. + */ +static int +init_event_rx(UAMP_STATE *uamp) +{ + struct ifreq ifr; + int fd = -1; + struct sockaddr_ll local; + int err; + int fd_pipe[2] = {-1, -1}; + pthread_t h; + + memset(&ifr, 0, sizeof(ifr)); + wl_get_interface_name(&ifr); + UAMP_PRINT(("ifr_name (%s)\n", ifr.ifr_name)); + + /* Create and bind socket to receive packets. */ + fd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE_BRCM)); + if (fd < 0) { + UAMP_ERROR(("%s: Cannot open socket", __FUNCTION__)); + return (-1); + } + + err = ioctl(fd, SIOCGIFINDEX, &ifr); + if (err < 0) { + UAMP_ERROR(("%s: Cannot get index %d\n", __FUNCTION__, err)); + close(fd); + return (-1); + } + + memset(&local, 0, sizeof(local)); + local.sll_family = AF_PACKET; + local.sll_protocol = htons(ETHER_TYPE_BRCM); + local.sll_ifindex = ifr.ifr_ifindex; + + if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) { + UAMP_ERROR(("%s: Cannot bind event socket", __FUNCTION__)); + close(fd); + return (-1); + } + + + /* Create pipe used to terminate receive packet thread. */ + if (pipe(fd_pipe) != 0) { + UAMP_ERROR(("%s: pipe failed\n", __FUNCTION__)); + goto cleanup; + } + + /* Save in instance memory. */ + uamp->evt_fd = fd; + uamp->evt_fd_pipe[0] = fd_pipe[0]; + uamp->evt_fd_pipe[1] = fd_pipe[1]; + + + /* Create message queue for received events. */ + + uamp->evt_q = mq_open(UAMP_EVT_Q_STR, O_RDWR | O_CREAT, 0666, NULL); + UAMP_PRINT(("evt_q(0x%x)\n", (int)uamp->evt_q)); + + + + /* Spawn event handling thread. */ + pthread_create(&h, NULL, event_thread, uamp); + + return (fd); + +cleanup: + if (-1 != fd) close(fd); + if (-1 != fd_pipe[0]) close(fd_pipe[0]); + if (-1 != fd_pipe[1]) close(fd_pipe[1]); + return (-1); +} + + +/* + * Cleanup event receive. + */ +static void +deinit_event_rx(UAMP_STATE *uamp) +{ + /* Cleanup the message queue. */ + mq_close(uamp->evt_q); + mq_unlink(UAMP_EVT_Q_STR); + + /* Kill the receive thread. */ + write(uamp->evt_fd_pipe[1], NULL, 0); + close(uamp->evt_fd_pipe[1]); +} + +/* + * Event receive thread. + */ +static void* +event_thread(void *param) +{ + UAMP_STATE *uamp = (UAMP_STATE *) param; + + UAMP_PRINT(("Start event wait loop\n")); + + while (1) { + fd_set rfds; /* fds for select */ + int last_fd; + int ret; + + FD_ZERO(&rfds); + FD_SET(uamp->evt_fd_pipe[0], &rfds); + FD_SET(uamp->evt_fd, &rfds); + last_fd = MAX(uamp->evt_fd_pipe[0], uamp->evt_fd); + + /* Wait on stop pipe or brcm event socket. */ + ret = select(last_fd+1, &rfds, NULL, NULL, NULL); + + /* Error processing */ + if (0 > ret) { + UAMP_ERROR(("%s: Unhandled signal on brcm event socket\n", __FUNCTION__)); + break; + } + + /* Stop processing. */ + if (FD_ISSET(uamp->evt_fd_pipe[0], &rfds)) { + UAMP_PRINT(("%s: stop rcvd on dispatcher pipe\n", __FUNCTION__)); + break; + } + + /* Event processing. */ + if (FD_ISSET(uamp->evt_fd, &rfds)) { + handle_event(uamp); + } + + } /* end-while(1) */ + + UAMP_PRINT(("%s: End event wait loop\n", __FUNCTION__)); + + close(uamp->evt_fd); + close(uamp->evt_fd_pipe[0]); + + UAMP_TRACE(("Exit %s\n", __FUNCTION__)); + return (NULL); +} + + +/* + * Process received event. + */ +static void +handle_event(UAMP_STATE *uamp) +{ + int bytes; + bcm_event_t *bcm_event; + wl_event_msg_t *wl_event; + uint8 *wl_evt_data; + uint32 datalen; + + /* Read event. */ + bytes = recv(uamp->evt_fd, uamp->event_data, sizeof(uamp->event_data), MSG_DONTWAIT); + + /* Error handling. */ + if (bytes < 0) { + if (errno != EINTR && errno != EAGAIN) { + UAMP_ERROR(("%s: Error reading event socket: %s\n", + __FUNCTION__, strerror(errno))); + return; + } + } + + if (bytes == 0) { + UAMP_ERROR(("%s: EOF on event socket", __FUNCTION__)); + return; + } + + + /* We're only interested in HCI events. */ + bcm_event = (bcm_event_t *)uamp->event_data; + if (ntoh32(bcm_event->event.event_type) != WLC_E_BTA_HCI_EVENT) { + return; + } + + UAMP_TRACE(("%s: received event!\n", __FUNCTION__)); + + + wl_event = &bcm_event->event; + wl_evt_data = (uint8 *)&wl_event[1]; + datalen = ntoh32(wl_event->datalen); + +#if (BRCM_BLUETOOTH_HOST == 1) + hcisu_handle_amp_evt_buf(wl_evt_data, datalen); +#else + { + tUAMP_EVT_DATA uamp_evt_data; + +#if (UAMP_DEBUG == 1) + /* Debug - dump event data. */ + { + unsigned int i; + UAMP_TRACE(("data(%d): ", datalen)); + for (i = 0; i < datalen; i++) + { + UAMP_TRACE(("0x%x ", wl_evt_data[i])); + } + UAMP_TRACE(("\n")); + } +#endif /* UAMP_DEBUG */ + + /* Post event to queue. Stack will de-queue it with call to UAMP_Read(). */ + if (mq_send(uamp->evt_q, (const char *)wl_evt_data, datalen, 0) != 0) { + /* Unable to queue packet */ + UAMP_ERROR(("%s: Unable to queue event packet!\n", __FUNCTION__)); + return; + } + + + /* Inform application stack of received event. */ + memset(&uamp_evt_data, 0, sizeof(uamp_evt_data)); + uamp_evt_data.channel = UAMP_CH_HCI_EVT; + g_uamp_mgr.callback(0, UAMP_EVT_RX_READY, &uamp_evt_data); + } +#endif /* BRCM_BLUETOOTH_HOST */ + +} + + +#define UAMP_TEST 1 +#if UAMP_TEST +int +main(int argc, char **argv) +{ + int ret; + + printf("Hello, world!\n"); + + if (argc != 2) { + usage(); + return (-1); + } + + if (strcmp(argv[1], "-a") == 0) { + ret = uamp_accept_test(); + } + else if (strcmp(argv[1], "-c") == 0) { + ret = uamp_create_test(); + } + else { + usage(); + return (-1); + } + + + return (ret); +} + +/* + * Usage display. + */ +static void usage(void) +{ + UAMP_PRINT(("Usage:\n")); + UAMP_PRINT(("\t uamp [-a | -c]\n")); + UAMP_PRINT(("\t\t -a: acceptor\n")); + UAMP_PRINT(("\t\t -c: creator\n")); +} + +#define WAIT_FOR_KEY(delay) \ + do { \ + usleep(1000*delay); \ + UAMP_PRINT(("Press key to continue\n")); \ + getchar(); \ + } \ + while (0); + + +/* + * Application callback for received events and packets. + */ +static void uamp_callback(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data) +{ + UINT8 buf[8192]; + amp_hci_ACL_data_t *data; + amp_hci_event_t *evt; + unsigned int i; + UINT16 num_bytes; + + UNUSED_PARAMETER(amp_evt); + + num_bytes = UAMP_Read(amp_id, buf, sizeof(buf), p_amp_evt_data->channel); + if (num_bytes != 0) { + if (p_amp_evt_data->channel == UAMP_CH_HCI_EVT) { + evt = (amp_hci_event_t *) buf; + UAMP_PRINT(("%s: evt - ecode(%d) plen(%d)\n", + __FUNCTION__, evt->ecode, evt->plen)); + + for (i = 0; i < evt->plen; i++) { + UAMP_PRINT(("0x%x ", evt->parms[i])); + } + UAMP_PRINT(("\n")); + } + else if (p_amp_evt_data->channel == UAMP_CH_HCI_DATA) { + data = (amp_hci_ACL_data_t *) buf; + UAMP_PRINT(("%s: data - dlen(%d)\n", __FUNCTION__, data->dlen)); + + for (i = 0; i < data->dlen; i++) { + UAMP_PRINT(("0x%x ", data->data[i])); + } + UAMP_PRINT(("\n")); + } + } + else { + UAMP_PRINT(("%s: UAMP_Read error\n", __FUNCTION__)); + } +} + + +/* This client is 00:90:4c:c6:02:5b. Remote is 00:90:4c:c5:06:79. */ +static int uamp_accept_test(void) +{ + uint8 set_event_mask_page_2_data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8 read_local_amp_assoc_data[] = {0, 0, 0}; + uint8 accept_physical_link_request_data[] = {0x11, 32, 3, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + uint8 write_remote_amp_assoc_data[] = {0x11, 0x0, 0x0, 0x24, 0x00, 0x04, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x01, 0x0f, + 0x00, 0x10, 0x09, 0x01, 0x06, 0x00, 0x00, 0x90, 0x4c, 0xc5, 0x06, + 0x79, 0x02, 0x09, 0x00, 0x55, 0x53, 0x20, 0xc9, 0x0c, 0x00, 0x01, + 0x01, 0x14}; + uint8 accept_logical_link_data[] = {0x11, 0x01, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8 tx_data[] = {7, 6, 5, 4, 3, 2, 1, 0}; + uint8 disconnect_logical_link_data[] = {0}; + uint8 disconnect_physical_link_data[] = {0x11, 0}; + + uint32 buf[64]; + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)buf; + amp_hci_ACL_data_t *pkt = (amp_hci_ACL_data_t *)buf; + + + UAMP_PRINT(("UAMP acceptor test\n")); + + + UAMP_Init(uamp_callback); + UAMP_Open(0); + + + /* HCI_Set_Event_Mask_Page_2 */ + uamp_write_cmd(HCI_Set_Event_Mask_Page_2, set_event_mask_page_2_data, + sizeof(set_event_mask_page_2_data), cmd, sizeof(buf)); + + /* Read_Local_AMP_ASSOC */ + uamp_write_cmd(HCI_Read_Local_AMP_ASSOC, read_local_amp_assoc_data, + sizeof(read_local_amp_assoc_data), cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Accept_Physical_Link_Request */ + uamp_write_cmd(HCI_Accept_Physical_Link_Request, accept_physical_link_request_data, + sizeof(accept_physical_link_request_data), cmd, sizeof(buf)); + + + /* This is specific to info obtained from the remote client. */ + /* Write_Remote_AMP_ASSOC */ + uamp_write_cmd(HCI_Write_Remote_AMP_ASSOC, write_remote_amp_assoc_data, + sizeof(write_remote_amp_assoc_data), cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Accept_Logical_Link */ + uamp_write_cmd(HCI_Accept_Logical_Link, accept_logical_link_data, + sizeof(accept_logical_link_data), cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* HCI_ACL_data */ + uamp_write_data(0 | HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS, tx_data, + sizeof(tx_data), pkt, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Disconnect_Logical_Link */ + uamp_write_cmd(HCI_Disconnect_Logical_Link, disconnect_logical_link_data, + sizeof(disconnect_logical_link_data), cmd, sizeof(buf)); + + /* Disconnect_Physical_Link */ + uamp_write_cmd(HCI_Disconnect_Physical_Link, disconnect_physical_link_data, + sizeof(disconnect_physical_link_data), cmd, sizeof(buf)); + + usleep(1000*1000); + UAMP_Close(0); + usleep(1000*1000); + UAMP_PRINT(("UAMP acceptor test done!\n")); + + return (0); +} + + +/* This client is 00:90:4c:c5:06:79. Remote is 00:90:4c:c6:02:5b. */ +static int uamp_create_test(void) +{ + uint8 set_event_mask_page_2_data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8 create_physical_link_data[] = {0x10, 32, 3, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + uint8 write_remote_amp_assoc_data[] = {0x10, 0x0, 0x0, 0x21, 0x00, 0x04, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x01, 0x0f, + 0x00, 0x10, 0x09, 0x01, 0x06, 0x00, 0x00, 0x90, 0x4c, 0xc6, 0x02, + 0x5b, 0x02, 0x06, 0x00, 0x55, 0x53, 0x20, 0xc9, 0x0c, 0x00}; + uint8 read_local_amp_assoc_data[] = {0x10, 0, 0, 100, 0}; + uint8 create_logical_link_data[] = {0x10, 0x01, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff}; + uint8 disconnect_logical_link_data[] = {0}; + uint8 disconnect_physical_link_data[] = {0x10, 0}; + uint8 tx_data[] = {0, 1, 2, 3, 4, 5, 6, 7}; + + uint32 buf[64]; + amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)buf; + amp_hci_ACL_data_t *pkt = (amp_hci_ACL_data_t *)buf; + + UAMP_PRINT(("UAMP creator test\n")); + + + UAMP_Init(uamp_callback); + + UAMP_Open(0); + + /* HCI_Set_Event_Mask_Page_2 */ + uamp_write_cmd(HCI_Set_Event_Mask_Page_2, set_event_mask_page_2_data, + sizeof(set_event_mask_page_2_data), cmd, sizeof(buf)); + + /* Read_Local_AMP_Info */ + uamp_write_cmd(HCI_Read_Local_AMP_Info, NULL, 0, cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Create_Physical_Link */ + uamp_write_cmd(HCI_Create_Physical_Link, create_physical_link_data, + sizeof(create_physical_link_data), cmd, sizeof(buf)); + + /* This is specific to info obtained from the remote client. */ + /* Write_Remote_AMP_ASSOC */ + uamp_write_cmd(HCI_Write_Remote_AMP_ASSOC, write_remote_amp_assoc_data, + sizeof(write_remote_amp_assoc_data), cmd, sizeof(buf)); + + + /* Spin for a bit. */ + usleep(1000*1000); + + + /* Read_Local_AMP_ASSOC */ + uamp_write_cmd(HCI_Read_Local_AMP_ASSOC, read_local_amp_assoc_data, + sizeof(read_local_amp_assoc_data), cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Create_Logical_Link */ + uamp_write_cmd(HCI_Create_Logical_Link, create_logical_link_data, + sizeof(create_logical_link_data), cmd, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* HCI_ACL_data */ + uamp_write_data(0 | HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS, tx_data, + sizeof(tx_data), pkt, sizeof(buf)); + WAIT_FOR_KEY(1000); + + /* Disconnect_Logical_Link */ + uamp_write_cmd(HCI_Disconnect_Logical_Link, disconnect_logical_link_data, + sizeof(disconnect_logical_link_data), cmd, sizeof(buf)); + + /* Disconnect_Physical_Link */ + uamp_write_cmd(HCI_Disconnect_Physical_Link, disconnect_physical_link_data, + sizeof(disconnect_physical_link_data), cmd, sizeof(buf)); + + usleep(1000*1000); + UAMP_Close(0); + usleep(1000*1000); + UAMP_PRINT(("UAMP creator test done!\n")); + + return (0); +} + + +/* + * Send UAMP command. + */ +static UINT16 uamp_write_cmd(uint16 opcode, uint8 *params, uint8 len, + amp_hci_cmd_t *cmd, unsigned int max_len) +{ + memset(cmd, 0, sizeof(amp_hci_cmd_t)); + cmd->plen = len; + cmd->opcode = opcode; + assert(HCI_CMD_PREAMBLE_SIZE + len <= max_len); + + if (len != 0) { + memcpy(cmd->parms, params, len); + } + + return (UAMP_Write(0, (UINT8 *)cmd, HCI_CMD_PREAMBLE_SIZE + len, UAMP_CH_HCI_CMD)); +} + + +/* + * Send UAMP data. + */ +static UINT16 uamp_write_data(uint16 handle, uint8 *data, uint8 len, + amp_hci_ACL_data_t *pkt, unsigned int max_len) +{ + memset(pkt, 0, sizeof(amp_hci_ACL_data_t)); + pkt->handle = handle; + pkt->dlen = len; + assert(HCI_ACL_DATA_PREAMBLE_SIZE + len <= max_len); + + if (len != 0) { + memcpy(pkt->data, data, len); + } + + return (UAMP_Write(0, (UINT8 *)pkt, HCI_ACL_DATA_PREAMBLE_SIZE + len, UAMP_CH_HCI_DATA)); +} +#endif /* UAMP_TEST */ diff --git a/src/wl/sys/wl_cfg80211.c b/src/wl/sys/wl_cfg80211.c new file mode 100644 index 0000000..de58c89 --- /dev/null +++ b/src/wl/sys/wl_cfg80211.c @@ -0,0 +1,5830 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + +#include <typedefs.h> +#include <linuxver.h> +#include <osl.h> +#include <linux/kernel.h> + +#include <bcmutils.h> +#include <bcmwifi.h> +#include <bcmendian.h> +#include <proto/ethernet.h> +#include <proto/802.11.h> +#include <linux/if_arp.h> +#include <asm/uaccess.h> + +#include <dngl_stats.h> +#include <dhd.h> +#include <dhdioctl.h> +#include <wlioctl.h> + +#include <proto/ethernet.h> +#include <dngl_stats.h> +#include <dhd.h> + +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/netdevice.h> +#include <linux/sched.h> +#include <linux/etherdevice.h> +#include <linux/wireless.h> +#include <linux/ieee80211.h> +#include <linux/wait.h> +#include <net/cfg80211.h> + +#include <net/rtnetlink.h> +#include <linux/mmc/sdio_func.h> +#include <linux/firmware.h> +#include <bcmsdbus.h> + +#include <wlioctl.h> +#include <wl_cfg80211.h> +#include <wl_cfgp2p.h> + +static struct sdio_func *cfg80211_sdio_func; +static struct wl_dev *wl_cfg80211_dev; + +u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; + +#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin" +#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt" +#define WL_TRACE(a) printk("%s ", __FUNCTION__); printk a +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAX_WAIT_TIME 3000 + + +/* Data Element Definitions */ +#define WPS_ID_CONFIG_METHODS 0x1008 +#define WPS_ID_REQ_TYPE 0x103A +#define WPS_ID_DEVICE_NAME 0x1011 +#define WPS_ID_VERSION 0x104A +#define WPS_ID_DEVICE_PWD_ID 0x1012 +#define WPS_ID_REQ_DEV_TYPE 0x106A +#define WPS_ID_PRIM_DEV_TYPE 0x1054 + +/* + * cfg80211_ops api/callback list + */ + +static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid); +static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request); +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); +static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params); +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev); +static s32 wl_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac, + struct station_info *sinfo); +static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, + s32 timeout); +static s32 wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask); +static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code); +static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + s32 dbm); +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); +#ifdef NEW_COMPAT_WIRELESS +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx, bool unicast, bool multicast); +#else +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx); +#endif /* NEW_COMPAT_WIRELESS */ +static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params); +static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr); +static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + void *cookie, void (*callback) (void *cookie, + struct key_params *params)); +static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx); +static s32 wl_cfg80211_resume(struct wiphy *wiphy); +static s32 wl_cfg80211_suspend(struct wiphy *wiphy); +static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa); +static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev); +/* + * event & event Q handlers for cfg80211 interfaces + */ +static s32 wl_create_event_handler(struct wl_priv *wl); +static void wl_destroy_event_handler(struct wl_priv *wl); +static s32 wl_event_handler(void *data); +static void wl_init_eq(struct wl_priv *wl); +static void wl_flush_eq(struct wl_priv *wl); +static void wl_lock_eq(struct wl_priv *wl); +static void wl_unlock_eq(struct wl_priv *wl); +static void wl_init_eq_lock(struct wl_priv *wl); +static void wl_init_event_handler(struct wl_priv *wl); +static struct wl_event_q *wl_deq_event(struct wl_priv *wl); +static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, + const wl_event_msg_t *msg, void *data); +static void wl_put_event(struct wl_event_q *e); +static void wl_wakeup_event(struct wl_priv *wl); +static s32 wl_notify_connect_status(struct wl_priv *wl, + struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_roaming_status(struct wl_priv *wl, + struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed); +static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); + +/* + * register/deregister sdio function + */ +struct sdio_func *wl_cfg80211_get_sdio_func(void); +static void wl_clear_sdio_func(void); + +/* + * ioctl utilites + */ +static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, + s32 buf_len); +static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name, + s8 *buf, s32 len); +static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); +static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name, + s32 *retval); +static s32 wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, + u32 len); + +/* + * cfg80211 set_wiphy_params utilities + */ +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); + +/* + * wl profile utilities + */ +static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, + void *data, s32 item); +static void *wl_read_prof(struct wl_priv *wl, s32 item); +static void wl_init_prof(struct wl_profile *prof); + +/* + * cfg80211 connect utilites + */ +static s32 wl_set_wpa_version(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_auth_type(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_cipher(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_key_mgmt(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme); +static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev); +static void wl_ch_to_chanspec(int ch, + struct wl_join_params *join_params, size_t *join_params_size); + +/* + * information element utilities + */ +static void wl_rst_ie(struct wl_priv *wl); +static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); +static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); +static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); +static u32 wl_get_ielen(struct wl_priv *wl); + +static s32 wl_mode_to_nl80211_iftype(s32 mode); + +static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, + struct device *dev); +static void wl_free_wdev(struct wl_priv *wl); + +static s32 wl_inform_bss(struct wl_priv *wl); +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi); +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev); + +static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, + struct key_params *params); +/* + * key indianess swap utilities + */ +static void swap_key_from_BE(struct wl_wsec_key *key); +static void swap_key_to_BE(struct wl_wsec_key *key); + +/* + * wl_priv memory init/deinit utilities + */ +static s32 wl_init_priv_mem(struct wl_priv *wl); +static void wl_deinit_priv_mem(struct wl_priv *wl); + +static void wl_delay(u32 ms); + +/* + * store/restore cfg80211 instance data + */ +static void wl_set_drvdata(struct wl_dev *dev, void *data); +static void *wl_get_drvdata(struct wl_dev *dev); + +/* + * ibss mode utilities + */ +static bool wl_is_ibssmode(struct wl_priv *wl); +static __used bool wl_is_ibssstarter(struct wl_priv *wl); + +/* + * dongle up/down , default configuration utilities + */ +static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); +static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e); +static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); +static void wl_link_up(struct wl_priv *wl); +static void wl_link_down(struct wl_priv *wl); +static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype); +static s32 __wl_cfg80211_up(struct wl_priv *wl); +static s32 __wl_cfg80211_down(struct wl_priv *wl); +static s32 wl_dongle_probecap(struct wl_priv *wl); +static void wl_init_conf(struct wl_conf *conf); +static s32 wl_dongle_eventmsg(struct net_device *ndev); + +/* + * dongle configuration utilities + */ +#ifndef EMBEDDED_PLATFORM +/* static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype); */ +static s32 wl_dongle_country(struct net_device *ndev, u8 ccode); +static s32 wl_dongle_up(struct net_device *ndev, u32 up); +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); +static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, + u32 dongle_align); +static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, + u32 bcn_timeout); +static s32 wl_dongle_eventmsg(struct net_device *ndev); +static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, + s32 scan_unassoc_time); +static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, + s32 arp_ol); +static s32 wl_pattern_atoh(s8 *src, s8 *dst); +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); +static s32 wl_update_wiphybands(struct wl_priv *wl); +#endif /* !EMBEDDED_PLATFORM */ +static __used void wl_dongle_poweron(struct wl_priv *wl); +static __used void wl_dongle_poweroff(struct wl_priv *wl); +static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock); + +/* + * iscan handler + */ +static void wl_iscan_timer(unsigned long data); +static void wl_term_iscan(struct wl_priv *wl); +static s32 wl_init_iscan(struct wl_priv *wl); +static s32 wl_iscan_thread(void *data); +static s32 wl_dev_iovar_setbuf(struct net_device *dev, s8 *iovar, + void *param, s32 paramlen, void *bufptr, + s32 buflen); +static s32 wl_dev_iovar_getbuf(struct net_device *dev, s8 *iovar, + void *param, s32 paramlen, void *bufptr, + s32 buflen); +static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, + u16 action); +static s32 wl_do_iscan(struct wl_priv *wl); +static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan); +static s32 wl_invoke_iscan(struct wl_priv *wl); +static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, + struct wl_scan_results **bss_list); +static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted); +static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan); +static s32 wl_iscan_done(struct wl_priv *wl); +static s32 wl_iscan_pending(struct wl_priv *wl); +static s32 wl_iscan_inprogress(struct wl_priv *wl); +static s32 wl_iscan_aborted(struct wl_priv *wl); +#ifdef NOT_YET +static s32 wl_dongle_save_eventmsg(struct wl_priv *wl); +static s32 wl_dongle_disable_eventmsg(struct wl_priv *wl); +static s32 wl_dongle_restore_eventmsg(struct wl_priv *wl); +#endif /* NOT_YET */ +/* + * fw/nvram downloading handler + */ +static void wl_init_fw(struct wl_fw_ctrl *fw); + +/* + * find most significant bit set + */ +static __used u32 wl_find_msb(u16 bit16); + +/* + * update pmklist to dongle + */ +static __used s32 wl_update_pmklist(struct net_device *dev, + struct wl_pmk_list *pmk_list, s32 err); + +static void wl_set_mpc(struct net_device *ndev, int mpc); + +/* + * debufs support + */ +static int wl_debugfs_add_netdev_params(struct wl_priv *wl); +static void wl_debugfs_remove_netdev(struct wl_priv *wl); + +/* + * rfkill support + */ +static int wl_setup_rfkill(struct wl_priv *wl); +static int wl_rfkill_set(void *data, bool blocked); + +#define WL_PRIV_GET() \ + ({ \ + struct wl_iface *ci = NULL; \ + if (unlikely(!(wl_cfg80211_dev && \ + (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \ + WL_ERR(("wl_cfg80211_dev is unavailable\n")); \ + BUG(); \ + } \ + ci_to_wl(ci); \ +}) + +#define CHECK_SYS_UP() \ +do { \ + struct wl_priv *wl = WL_PRIV_GET(); \ + if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \ + WL_INFO(("device is not ready : status (%d)\n", \ + (int)wl->status)); \ + return -EIO; \ + } \ +} while (0) + +extern int dhd_wait_pend8021x(struct net_device *dev); + +#if (WL_DBG_LEVEL > 0) +#define WL_DBG_ESTR_MAX 50 +static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { + "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", + "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", + "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", + "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", + "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", + "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", + "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", + "PFN_NET_LOST", + "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", + "IBSS_ASSOC", + "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", + "PROBREQ_MSG", + "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", + "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", + "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", + "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", + "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", + "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", + "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", + "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", + "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", + "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", + "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" +}; +#endif /* WL_DBG_LEVEL */ + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .bitrate = RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +static struct ieee80211_rate __wl_rates[] = { + RATETAB_ENT(WLC_RATE_1M, 0), + RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(WLC_RATE_6M, 0), + RATETAB_ENT(WLC_RATE_9M, 0), + RATETAB_ENT(WLC_RATE_12M, 0), + RATETAB_ENT(WLC_RATE_18M, 0), + RATETAB_ENT(WLC_RATE_24M, 0), + RATETAB_ENT(WLC_RATE_36M, 0), + RATETAB_ENT(WLC_RATE_48M, 0), + RATETAB_ENT(WLC_RATE_54M, 0), +}; + +#define wl_a_rates (__wl_rates + 4) +#define wl_a_rates_size 8 +#define wl_g_rates (__wl_rates + 0) +#define wl_g_rates_size 12 + +static struct ieee80211_channel __wl_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel __wl_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_channel __wl_5ghz_n_channels[] = { + CHAN5G(32, 0), CHAN5G(34, 0), + CHAN5G(36, 0), CHAN5G(38, 0), + CHAN5G(40, 0), CHAN5G(42, 0), + CHAN5G(44, 0), CHAN5G(46, 0), + CHAN5G(48, 0), CHAN5G(50, 0), + CHAN5G(52, 0), CHAN5G(54, 0), + CHAN5G(56, 0), CHAN5G(58, 0), + CHAN5G(60, 0), CHAN5G(62, 0), + CHAN5G(64, 0), CHAN5G(66, 0), + CHAN5G(68, 0), CHAN5G(70, 0), + CHAN5G(72, 0), CHAN5G(74, 0), + CHAN5G(76, 0), CHAN5G(78, 0), + CHAN5G(80, 0), CHAN5G(82, 0), + CHAN5G(84, 0), CHAN5G(86, 0), + CHAN5G(88, 0), CHAN5G(90, 0), + CHAN5G(92, 0), CHAN5G(94, 0), + CHAN5G(96, 0), CHAN5G(98, 0), + CHAN5G(100, 0), CHAN5G(102, 0), + CHAN5G(104, 0), CHAN5G(106, 0), + CHAN5G(108, 0), CHAN5G(110, 0), + CHAN5G(112, 0), CHAN5G(114, 0), + CHAN5G(116, 0), CHAN5G(118, 0), + CHAN5G(120, 0), CHAN5G(122, 0), + CHAN5G(124, 0), CHAN5G(126, 0), + CHAN5G(128, 0), CHAN5G(130, 0), + CHAN5G(132, 0), CHAN5G(134, 0), + CHAN5G(136, 0), CHAN5G(138, 0), + CHAN5G(140, 0), CHAN5G(142, 0), + CHAN5G(144, 0), CHAN5G(145, 0), + CHAN5G(146, 0), CHAN5G(147, 0), + CHAN5G(148, 0), CHAN5G(149, 0), + CHAN5G(150, 0), CHAN5G(151, 0), + CHAN5G(152, 0), CHAN5G(153, 0), + CHAN5G(154, 0), CHAN5G(155, 0), + CHAN5G(156, 0), CHAN5G(157, 0), + CHAN5G(158, 0), CHAN5G(159, 0), + CHAN5G(160, 0), CHAN5G(161, 0), + CHAN5G(162, 0), CHAN5G(163, 0), + CHAN5G(164, 0), CHAN5G(165, 0), + CHAN5G(166, 0), CHAN5G(168, 0), + CHAN5G(170, 0), CHAN5G(172, 0), + CHAN5G(174, 0), CHAN5G(176, 0), + CHAN5G(178, 0), CHAN5G(180, 0), + CHAN5G(182, 0), CHAN5G(184, 0), + CHAN5G(186, 0), CHAN5G(188, 0), + CHAN5G(190, 0), CHAN5G(192, 0), + CHAN5G(194, 0), CHAN5G(196, 0), + CHAN5G(198, 0), CHAN5G(200, 0), + CHAN5G(202, 0), CHAN5G(204, 0), + CHAN5G(206, 0), CHAN5G(208, 0), + CHAN5G(210, 0), CHAN5G(212, 0), + CHAN5G(214, 0), CHAN5G(216, 0), + CHAN5G(218, 0), CHAN5G(220, 0), + CHAN5G(222, 0), CHAN5G(224, 0), + CHAN5G(226, 0), CHAN5G(228, 0), +}; + +static struct ieee80211_supported_band __wl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + .channels = __wl_2ghz_channels, + .n_channels = ARRAY_SIZE(__wl_2ghz_channels), + .bitrates = wl_g_rates, + .n_bitrates = wl_g_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_a = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_a_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_n = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_n_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static const u32 __wl_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = { + /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, +}; + +static void swap_key_from_BE(struct wl_wsec_key *key) +{ + key->index = htod32(key->index); + key->len = htod32(key->len); + key->algo = htod32(key->algo); + key->flags = htod32(key->flags); + key->rxiv.hi = htod32(key->rxiv.hi); + key->rxiv.lo = htod16(key->rxiv.lo); + key->iv_initialized = htod32(key->iv_initialized); +} + +static void swap_key_to_BE(struct wl_wsec_key *key) +{ + key->index = dtoh32(key->index); + key->len = dtoh32(key->len); + key->algo = dtoh32(key->algo); + key->flags = dtoh32(key->flags); + key->rxiv.hi = dtoh32(key->rxiv.hi); + key->rxiv.lo = dtoh16(key->rxiv.lo); + key->iv_initialized = dtoh32(key->iv_initialized); +} + +static s32 +wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len) +{ + struct ifreq ifr; + struct wl_ioctl ioc; + mm_segment_t fs; + s32 err = 0; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t)&ioc; + + fs = get_fs(); + set_fs(get_ds()); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#else + err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + set_fs(fs); + + return err; +} + +/* For debug: Dump the contents of the encoded wps ie buffe */ +static void +wl_dbg_dump_wps_ie(char *wps_ie) +{ + #define WPS_IE_FIXED_LEN 6 + u16 len = (u16) wps_ie[TLV_LEN_OFF]; + u8 *subel = wps_ie+ WPS_IE_FIXED_LEN; + u16 subelt_id; + u16 subelt_len; + u16 val; + u8 *valptr = (uint8*) &val; + + WL_DBG(("wps_ie len=%d\n", len)); + + len -= 4; /* for the WPS IE's OUI, oui_type fields */ + + while (len >= 4) { /* must have attr id, attr len fields */ + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_id = HTON16(val); + + valptr[0] = *subel++; + valptr[1] = *subel++; + subelt_len = HTON16(val); + + len -= 4; /* for the attr id, attr len fields */ + len -= subelt_len; /* for the remaining fields in this attribute */ + WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", + subel, subelt_id, subelt_len)); + + if (subelt_id == WPS_ID_VERSION) { + WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); + } else if (subelt_id == WPS_ID_REQ_TYPE) { + WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); + } else if (subelt_id == WPS_ID_CONFIG_METHODS) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); + } else if (subelt_id == WPS_ID_DEVICE_NAME) { + char devname[100]; + memcpy(devname, subel, subelt_len); + devname[subelt_len] = '\0'; + WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", + devname, subelt_len)); + } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { + valptr[0] = *subel; + valptr[1] = *(subel + 1); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); + valptr[0] = *(subel + 6); + valptr[1] = *(subel + 7); + WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); + } else { + WL_DBG((" unknown attr 0x%x\n", subelt_id)); + } + + subel += subelt_len; + } +} + +static struct net_device * +wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 err; + s32 timeout = -1; + s32 wlif_type; + s32 index = 0; + chanspec_t chspec; + struct wl_priv *wl = WL_PRIV_GET(); + struct net_device *_ndev; + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + + WL_DBG(("if name: %s, type: %d\n", name, type)); + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + WL_ERR(("Unsupported interface type\n")); + wl->conf->mode = WL_MODE_IBSS; + return NULL; + case NL80211_IFTYPE_MONITOR: + return wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + wlif_type = WL_P2P_IF_CLIENT; + wl->conf->mode = WL_MODE_BSS; + break; + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP: + wlif_type = WL_P2P_IF_GO; + wl->conf->mode = WL_MODE_AP; + break; + default: + WL_ERR(("Unsupported interface type\n")); + return NULL; + break; + } + + if (!name) { + WL_ERR(("name is NULL\n")); + return NULL; + } + + if (!wl->p2p_on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + wl->p2p_on = true; + wl_cfgp2p_init_discovery(wl); + } + + memset(wl->p2p_vir_ifname, 0, IFNAMSIZ); + strncpy(wl->p2p_vir_ifname, name, IFNAMSIZ - 1); + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p_dev_addr, &wl->p2p_int_addr); + + /* Temporary use channel 11, in case GO will be changed with set_channel API */ + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + + /* For P2P mode, use P2P-specific driver features to create the + * bss: "wl p2p_ifadd" + */ + clear_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); + err = wl_cfgp2p_ifadd(wl, &wl->p2p_int_addr, htod32(wlif_type), chspec); + + if (unlikely(err)) + return ERR_PTR(-ENOMEM); + + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status) == TRUE), + msecs_to_jiffies(MAX_WAIT_TIME)); + if (timeout > 0 && test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status)) { + + struct wireless_dev *vwdev; + vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); + if (unlikely(!vwdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return ERR_PTR(-ENOMEM); + } + vwdev->wiphy = wl->wdev->wiphy; + WL_INFO((" virtual interface(%s) is created \n", wl->p2p_vir_ifname)); + index = alloc_idx_vwdev(wl); + wl->vwdev[index] = vwdev; + vwdev->iftype = + (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION + : NL80211_IFTYPE_AP; + _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); + _ndev->ieee80211_ptr = vwdev; + SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); + vwdev->netdev = _ndev; + set_bit(WL_STATUS_READY, &wl->status); + wl->p2p_vif_created = TRUE; + wl = wdev_to_wl(vwdev); + return _ndev; + + + } else { + clear_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); + WL_ERR((" virtual interface(%s) is not created \n", wl->p2p_vir_ifname)); + memset(wl->p2p_vir_ifname, '\0', IFNAMSIZ); + wl->p2p_vif_created = FALSE; + } + + return ERR_PTR(-ENODEV); +} + + +static s32 +wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) +{ + struct ether_addr p2p_mac; + struct wl_priv *wl = WL_PRIV_GET(); + memcpy(p2p_mac.octet, wl->p2p_int_addr.octet, ETHER_ADDR_LEN); + if (wl->p2p_vif_created) { + if (test_bit(WL_STATUS_SCANNING, &wl->status)) { + wl_cfg80211_scan_abort(wl, dev); + } + wl_cfgp2p_ifdel(wl, &p2p_mac); + + } + + WL_DBG(("Done\n")); + return 0; +} + +static s32 +wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + s32 ap = 0; + s32 infra = 0; + s32 err = BCME_OK; + chanspec_t chspec; + s32 timeout = -1; + s32 wlif_type; + struct wl_priv *wl = WL_PRIV_GET(); + CHECK_SYS_UP(); + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + ap = 1; + WL_ERR(("type (%d) : currently we do not support this type\n", + type)); + break; + case NL80211_IFTYPE_ADHOC: + wl->conf->mode = WL_MODE_IBSS; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + wl->conf->mode = WL_MODE_BSS; + infra = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + wl->conf->mode = WL_MODE_AP; + ap = 1; + break; + default: + return -EINVAL; + } + + + if (ap && wl->p2p_vif_created) { + WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p_vif_created, + wl->p2p_on)); + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT; + WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type)); + set_bit(WLP2P_STATUS_IF_CHANGING, &wl->p2p_status); + clear_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status); + err = wl_cfgp2p_ifchange(wl, &wl->p2p_int_addr, htod32(wlif_type), chspec); + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (test_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status) == TRUE), + msecs_to_jiffies(MAX_WAIT_TIME)); + + clear_bit(WLP2P_STATUS_IF_CHANGING, &wl->p2p_status); + clear_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status); + } + + ndev->ieee80211_ptr->iftype = type; + return 0; +} + +s32 +wl_cfg80211_notify_ifadd(struct net_device *net) +{ + struct wl_priv *wl = WL_PRIV_GET(); + s32 ret = BCME_OK; + if (!net || !net->name) { + WL_ERR(("net is NULL\n")); + return 0; + } + + WL_DBG(("IF_ADD event called from dongle, old interface name: %s, new name: %s\n", + net->name, wl->p2p_vir_ifname)); + /* Assign the net device to CONNECT BSSCFG */ + strncpy(net->name, wl->p2p_vir_ifname, IFNAMSIZ - 1); + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net; + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = P2PAPI_BSSCFG_CONNECTION; + set_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); + wake_up_interruptible(&wl->dongle_event_wait); + return ret; +} + +s32 +wl_cfg80211_notify_ifdel(struct net_device *net) +{ + struct wl_priv *wl = WL_PRIV_GET(); + + if (!net || !net->name) { + WL_DBG(("net is NULL\n")); + return 0; + } + + WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n", + net->name, wl->p2p_vir_ifname)); + if (wl->p2p_vif_created) { + s32 index = 0; + memset(wl->p2p_vir_ifname, '\0', IFNAMSIZ); + index = wl_cfgp2p_find_idx(wl, net); + wl_to_p2p_bss_ndev(wl, index) = NULL; + wl_to_p2p_bss_bssidx(wl, index) = 0; + wl->p2p_vif_created = FALSE; + wl_cfgp2p_clear_management_ie(wl, + index); + index = get_idx_vwdev_by_netdev(wl, net); + WL_DBG(("index : %d\n", index)); + if (index >= 0) { + free_vwdev_by_index(wl, index); + } + } + return 0; +} + + +s32 +wl_cfg80211_is_progress_ifchange(void) +{ + s32 is_progress = 0; + struct wl_priv *wl = WL_PRIV_GET(); + if (test_bit(WLP2P_STATUS_IF_CHANGING, &wl->p2p_status)) + is_progress = 1; + return is_progress; +} + + +s32 +wl_cfg80211_notify_ifchange(void) +{ + struct wl_priv *wl = WL_PRIV_GET(); + if (test_bit(WLP2P_STATUS_IF_CHANGING, &wl->p2p_status)) { + set_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status); + wake_up_interruptible(&wl->dongle_event_wait); + } + return 0; +} + +static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid) +{ + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = 0; + params->nprobes = -1; + params->active_time = -1; + params->passive_time = -1; + params->home_time = -1; + params->channel_num = 0; + + params->nprobes = htod32(params->nprobes); + params->active_time = htod32(params->active_time); + params->passive_time = htod32(params->passive_time); + params->home_time = htod32(params->home_time); + if (ssid && ssid->SSID_len) + memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); + +} + +static s32 +wl_dev_iovar_setbuf(struct net_device *dev, s8 * iovar, void *param, + s32 paramlen, void *bufptr, s32 buflen) +{ + s32 iolen; + + iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); + BUG_ON(unlikely(!iolen)); + + return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen); +} + +static s32 +wl_dev_iovar_getbuf(struct net_device *dev, s8 * iovar, void *param, + s32 paramlen, void *bufptr, s32 buflen) +{ + s32 iolen; + + iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); + BUG_ON(unlikely(!iolen)); + + return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen); +} + +static s32 +wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) +{ + s32 params_size = + (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); + struct wl_iscan_params *params; + s32 err = 0; + + if (ssid && ssid->SSID_len) + params_size += sizeof(struct wlc_ssid); + params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); + if (unlikely(!params)) + return -ENOMEM; + memset(params, 0, params_size); + BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN)); + + wl_iscan_prep(¶ms->params, ssid); + + params->version = htod32(ISCAN_REQ_VERSION); + params->action = htod16(action); + params->scan_duration = htod16(0); + + /* params_size += offsetof(wl_iscan_params_t, params); */ + err = wl_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size, + iscan->ioctl_buf, WLC_IOCTL_SMLEN); + if (unlikely(err)) { + if (err == -EBUSY) { + WL_INFO(("system busy : iscan canceled\n")); + } else { + WL_ERR(("error (%d)\n", err)); + } + } + kfree(params); + return err; +} + +static s32 wl_do_iscan(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); + struct net_device *ndev = wl_to_prmry_ndev(wl); + struct wlc_ssid ssid; + s32 passive_scan; + s32 err = 0; + + /* Broadcast scan by default */ + memset(&ssid, 0, sizeof(ssid)); + + iscan->state = WL_ISCAN_STATE_SCANING; + + passive_scan = wl->active_scan ? 0 : 1; + err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (unlikely(err)) { + WL_DBG(("error (%d)\n", err)); + return err; + } + wl_set_mpc(ndev, 0); + wl->iscan_kickstart = true; + wl_run_iscan(iscan, &ssid, WL_SCAN_ACTION_START); + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 +wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint16 action) +{ + s32 err = BCME_OK; + s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); + wl_escan_params_t *params; + struct cfg80211_scan_request *scan_request = wl->scan_request; + u32 num_chans = 0; + s32 search_state = WL_P2P_DISC_ST_SCAN; + u32 i; + u16 *default_chan_list = NULL; + WL_DBG(("Enter \n")); + + + if ((ndev == wl_to_prmry_ndev(wl)) && + !wl->p2p_scan) { + /* LEGACY SCAN TRIGGER */ + WL_DBG(("LEGACY SCAN START\n")); + if (ssid && ssid->SSID_len) { + params_size += sizeof(wlc_ssid_t); + } + params = (wl_escan_params_t *) kmalloc(params_size, GFP_KERNEL); + + if (params == NULL) + return -ENOMEM; + + memset(params, 0, params_size); + memcpy(¶ms->params.bssid, ðer_bcast, ETHER_ADDR_LEN); + params->params.bss_type = DOT11_BSSTYPE_ANY; + params->params.scan_type = 0; + params->params.nprobes = htod32(-1); + params->params.active_time = htod32(-1); + params->params.passive_time = htod32(-1); + params->params.home_time = htod32(-1); + params->params.channel_num = 0; + if (ssid && ssid->SSID_len) { + memcpy(params->params.ssid.SSID, ssid->SSID, ssid->SSID_len); + params->params.ssid.SSID_len = htod32(ssid->SSID_len); + } + params->version = htod32(ESCAN_REQ_VERSION); + params->action = htod16(action); + params->sync_id = htod16(0x1234); + wl_dev_iovar_setbuf(ndev, "escan", params, params_size, + wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); + kfree(params); + } + else if (wl->p2p_on && wl->p2p_scan) { + /* P2P SCAN TRIGGER */ + if (scan_request && scan_request->n_channels) { + num_chans = scan_request->n_channels; + WL_INFO((" chann number : %d\n", num_chans)); + default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), + GFP_KERNEL); + if (default_chan_list == NULL) { + WL_ERR(("channel list allocation failed \n")); + err = -ENOMEM; + goto exit; + } + for (i = 0; i < num_chans; i++) + { + default_chan_list[i] = + ieee80211_frequency_to_channel( + scan_request->channels[i]->center_freq); + } + if (num_chans == 3 && ( + (default_chan_list[0] == SOCIAL_CHAN_1) && + (default_chan_list[1] == SOCIAL_CHAN_2) && + (default_chan_list[2] == SOCIAL_CHAN_3))) { + /* SOCIAL CHANNELS 1, 6, 11 */ + search_state = WL_P2P_DISC_ST_SEARCH; + WL_INFO(("P2P SEARCH PHASE START \n")); + } else { + WL_INFO(("P2P SCAN STATE START \n")); + } + + } + err = wl_cfgp2p_escan(wl, wl->active_scan, num_chans, default_chan_list, + search_state, action, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + kfree(default_chan_list); + } +exit: + return err; +} + + +static s32 +wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wlc_ssid_t *ssid) +{ + + + s32 err = BCME_OK; + s32 passive_scan; + wl_scan_results_t *results; + WL_DBG(("Enter \n")); + + wl->escan_info.wiphy = wiphy; + wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; + passive_scan = wl->active_scan ? 0 : 1; + err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (unlikely(err)) { + WL_DBG(("error (%d)\n", err)); + return err; + } + results = (wl_scan_results_t *) wl->escan_info.escan_buf; + results->version = 0; + results->count = 0; + results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; + + wl_set_mpc(ndev, 0); + wl_run_escan(wl, ndev, ssid, WL_SCAN_ACTION_START); + return err; +} + +static s32 +__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct cfg80211_ssid *ssids; + struct wl_scan_req *sr = wl_to_sr(wl); + wlc_ssid_t ssid_info; + s32 passive_scan; + bool iscan_req; + bool escan_req; + bool spec_scan; + s32 err = 0; + + if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) { + WL_ERR(("Scanning already : status (%d)\n", (int)wl->status)); + return -EAGAIN; + } + if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) { + WL_ERR(("Scanning being aborted : status (%d)\n", + (int)wl->status)); + return -EAGAIN; + } + + WL_DBG(("wiphy (%p)\n", wiphy)); + + iscan_req = false; + spec_scan = false; + if (request) { /* scan bss */ + ssids = request->ssids; + if (wl->iscan_on && (!ssids || !ssids->ssid_len)) { + iscan_req = true; + } else if (wl->escan_on) { + escan_req = true; + if (ssids->ssid_len && IS_P2P_SSID(ssids->ssid)) { + /* p2p scan trigger */ + if (wl->p2p_on == false) { + /* p2p on at the first time */ + wl->p2p_on = true; + wl_cfgp2p_set_firm_p2p(wl); + } + + wl->p2p_scan = true; + + } else { + /* legacy scan trigger + * So, we have to disable p2p discovery if p2p discovery is on + */ + wl->p2p_scan = false; + /* If Netdevice is not equals to primary and p2p is on + * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. + */ + if (wl->p2p_on && (ndev != wl_to_prmry_ndev(wl))) + wl->p2p_scan = true; + + if (wl->p2p_scan == false) { + if (test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status)) { + err = wl_cfgp2p_discover_enable_search(wl, FALSE); + if (unlikely(err)) { + goto scan_out; + } + + } + } + } + } + } else { /* scan in ibss */ + /* we don't do iscan in ibss */ + ssids = this_ssid; + } + wl->scan_request = request; + set_bit(WL_STATUS_SCANNING, &wl->status); + if (iscan_req) { + err = wl_do_iscan(wl); + if (likely(!err)) + return err; + else + goto scan_out; + } else if (escan_req) { + WL_DBG(("ssid \"%s\", ssid_len (%d)\n", + ssids->ssid, ssids->ssid_len)); + + memcpy(ssid_info.SSID, ssids->ssid, ssids->ssid_len); + ssid_info.SSID_len = ssids->ssid_len; + + if (wl->p2p_on && wl->p2p_scan) { + + err = wl_cfgp2p_enable_discovery(wl, request->ie, request->ie_len); + + if (unlikely(err)) { + goto scan_out; + } + } + err = wl_do_escan(wl, wiphy, ndev, &ssid_info); + if (likely(!err)) + return err; + else + goto scan_out; + + + } else { + memset(&sr->ssid, 0, sizeof(sr->ssid)); + sr->ssid.SSID_len = + min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); + if (sr->ssid.SSID_len) { + memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); + sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); + WL_DBG(("Specific scan ssid=\"%s\" len=%d\n", + sr->ssid.SSID, sr->ssid.SSID_len)); + spec_scan = true; + } else { + WL_DBG(("Broadcast scan\n")); + } + WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); + passive_scan = wl->active_scan ? 0 : 1; + err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); + goto scan_out; + } + wl_set_mpc(ndev, 0); + err = wl_dev_ioctl(ndev, WLC_SCAN, &sr->ssid, + sizeof(sr->ssid)); + if (err) { + if (err == -EBUSY) { + WL_INFO(("system busy : scan for \"%s\" " + "canceled\n", sr->ssid.SSID)); + } else { + WL_ERR(("WLC_SCAN error (%d)\n", err)); + } + wl_set_mpc(ndev, 1); + goto scan_out; + } + } + + return 0; + +scan_out: + clear_bit(WL_STATUS_SCANNING, &wl->status); + wl->scan_request = NULL; + return err; +} + +static s32 +wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + s32 err = 0; + + WL_DBG(("Enter \n")); + CHECK_SYS_UP(); + err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); + if (unlikely(err)) { + WL_DBG(("scan error (%d)\n", err)); + return err; + } + + return err; +} + +static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) +{ + s8 buf[WLC_IOCTL_SMLEN]; + u32 len; + s32 err = 0; + + val = htod32(val); + len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); + BUG_ON(unlikely(!len)); + + err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + + return err; +} + +static s32 +wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) +{ + union { + s8 buf[WLC_IOCTL_SMLEN]; + s32 val; + } var; + u32 len; + u32 data_null; + s32 err = 0; + + len = bcm_mkiovar(name, (char *)(&data_null), 0, + (char *)(&var), sizeof(var.buf)); + BUG_ON(unlikely(!len)); + err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + *retval = dtoh32(var.val); + + return err; +} + +static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) +{ + s32 err = 0; + + err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) +{ + s32 err = 0; + + err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) +{ + s32 err = 0; + u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); + + retry = htod32(retry); + err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry)); + if (unlikely(err)) { + WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct wl_priv *wl = wiphy_to_wl(wiphy); + struct net_device *ndev = wl_to_prmry_ndev(wl); + s32 err = 0; + + CHECK_SYS_UP(); + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (wl->conf->rts_threshold != wiphy->rts_threshold)) { + wl->conf->rts_threshold = wiphy->rts_threshold; + err = wl_set_rts(ndev, wl->conf->rts_threshold); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (wl->conf->frag_threshold != wiphy->frag_threshold)) { + wl->conf->frag_threshold = wiphy->frag_threshold; + err = wl_set_frag(ndev, wl->conf->frag_threshold); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_RETRY_LONG && + (wl->conf->retry_long != wiphy->retry_long)) { + wl->conf->retry_long = wiphy->retry_long; + err = wl_set_retry(ndev, wl->conf->retry_long, true); + if (!err) + return err; + } + if (changed & WIPHY_PARAM_RETRY_SHORT && + (wl->conf->retry_short != wiphy->retry_short)) { + wl->conf->retry_short = wiphy->retry_short; + err = wl_set_retry(ndev, wl->conf->retry_short, false); + if (!err) { + return err; + } + } + + return err; +} + +static s32 +wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct cfg80211_bss *bss; + struct ieee80211_channel *chan; + struct wl_join_params join_params; + struct cfg80211_ssid ssid; + s32 scan_retry = 0; + s32 err = 0; + + WL_TRACE(("In\n")); + CHECK_SYS_UP(); + if (params->bssid) { + WL_ERR(("Invalid bssid\n")); + return -EOPNOTSUPP; + } + bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); + if (!bss) { + memcpy(ssid.ssid, params->ssid, params->ssid_len); + ssid.ssid_len = params->ssid_len; + do { + if (unlikely + (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == + -EBUSY)) { + wl_delay(150); + } else { + break; + } + } while (++scan_retry < WL_SCAN_RETRY_MAX); + /* to allow scan_inform to paropagate to cfg80211 plane */ + rtnl_unlock(); + + /* wait 4 secons till scan done.... */ + schedule_timeout_interruptible(4 * HZ); + rtnl_lock(); + bss = cfg80211_get_ibss(wiphy, NULL, + params->ssid, params->ssid_len); + } + if (bss) { + wl->ibss_starter = false; + WL_DBG(("Found IBSS\n")); + } else { + wl->ibss_starter = true; + } + chan = params->channel; + if (chan) + wl->channel = ieee80211_frequency_to_channel(chan->center_freq); + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + memset(&join_params, 0, sizeof(join_params)); + memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, + params->ssid_len); + join_params.ssid.SSID_len = htod32(params->ssid_len); + if (params->bssid) + memcpy(&join_params.params.bssid, params->bssid, + ETHER_ADDR_LEN); + else + memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + + err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, + sizeof(join_params)); + if (unlikely(err)) { + WL_ERR(("Error (%d)\n", err)); + return err; + } + return err; +} + +static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_priv *wl = WL_PRIV_GET(); + s32 err = 0; + + CHECK_SYS_UP(); + wl_link_down(wl); + + return err; +} + +static s32 +wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + val = WPA_AUTH_PSK; /* | WPA_AUTH_UNSPECIFIED; */ + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + val = WPA2_AUTH_PSK; /* | WPA2_AUTH_UNSPECIFIED ; */ + else + val = WPA_AUTH_DISABLED; + + if (is_wps_conn(sme)) + val = WPA_AUTH_DISABLED; + + WL_DBG(("setting wpa_auth to 0x%0x\n", val)); + err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, val); + if (unlikely(err)) { + WL_ERR(("set wpa_auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(wl, WL_PROF_SEC); + sec->wpa_versions = sme->crypto.wpa_versions; + return err; +} + +static s32 +wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + val = 0; + WL_DBG(("open system\n")); + break; + case NL80211_AUTHTYPE_SHARED_KEY: + val = 1; + WL_DBG(("shared key\n")); + break; + case NL80211_AUTHTYPE_AUTOMATIC: + val = 2; + WL_DBG(("automatic\n")); + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + WL_DBG(("network eap\n")); + default: + val = 2; + WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); + break; + } + + err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, val); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + sec = wl_read_prof(wl, WL_PROF_SEC); + sec->auth_type = sme->auth_type; + return err; +} + +static s32 +wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + s32 pval = 0; + s32 gval = 0; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + if (sme->crypto.n_ciphers_pairwise) { + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + pval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + pval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + pval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + pval = AES_ENABLED; + break; + default: + WL_ERR(("invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + } + if (sme->crypto.cipher_group) { + switch (sme->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + gval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + gval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + gval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + gval = AES_ENABLED; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } + + WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); + + if (is_wps_conn(sme)) { + err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, 4); + } else { + err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, pval | gval); + } + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + sec = wl_read_prof(wl, WL_PROF_SEC); + sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + sec->cipher_group = sme->crypto.cipher_group; + + return err; +} + +static s32 +wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + s32 val = 0; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + if (sme->crypto.n_akm_suites) { + err = wl_dev_intvar_get(dev, "wpa_auth", &val); + if (unlikely(err)) { + WL_ERR(("could not get wpa_auth (%d)\n", err)); + return err; + } + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } + + WL_DBG(("setting wpa_auth to %d\n", val)); + + err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, val); + if (unlikely(err)) { + WL_ERR(("could not set wpa_auth (%d)\n", err)); + return err; + } + } + sec = wl_read_prof(wl, WL_PROF_SEC); + sec->wpa_auth = sme->crypto.akm_suites[0]; + + return err; +} + +static s32 +wl_set_set_sharedkey(struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + struct wl_wsec_key key; + s32 val; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + WL_DBG(("key len (%d)\n", sme->key_len)); + if (sme->key_len) { + sec = wl_read_prof(wl, WL_PROF_SEC); + WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise)); + if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | + NL80211_WPA_VERSION_2)) && + (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | + WLAN_CIPHER_SUITE_WEP104))) { + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (unlikely(key.len > sizeof(key.data))) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, sme->key, key.len); + key.flags = WL_PRIMARY_KEY; + switch (sec->cipher_pairwise) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + break; + default: + WL_ERR(("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0])); + return -EINVAL; + } + /* Set the new key/index */ + WL_DBG(("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo)); + WL_DBG(("key \"%s\"\n", key.data)); + swap_key_from_BE(&key); + err = wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { + WL_DBG(("set auth_type to shared key\n")); + val = 1; /* shared key */ + err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, val); + if (unlikely(err)) { + WL_ERR(("set auth failed (%d)\n", err)); + return err; + } + } + } + } + return err; +} + +static s32 +wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct ieee80211_channel *chan = sme->channel; + struct wl_join_params join_params; + size_t join_params_size; + s32 err = 0; + + WL_TRACE(("In\n")); + if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { + /* we only allow to connect using virtual interface in case of P2P */ + if (wl->p2p_on && is_wps_conn(sme)) { + + WL_DBG(("p2p index : %d\n", wl_cfgp2p_find_idx(wl, dev))); + /* Have to apply WPS IE + P2P IE in assoc req frame */ + wl_cfgp2p_set_managment_ie(wl, dev, + wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG, + wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie, + wl_to_p2p_bss_saved_ie(wl, + P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len); + wl_cfgp2p_set_managment_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), + VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); + } + } else { + WL_ERR(("No P2PIE in beacon \n")); + } + + + CHECK_SYS_UP(); + if (unlikely(!sme->ssid)) { + WL_ERR(("Invalid ssid\n")); + return -EOPNOTSUPP; + } + if (chan) { + wl->channel = ieee80211_frequency_to_channel(chan->center_freq); + WL_DBG(("channel (%d), center_req (%d)\n", wl->channel, + chan->center_freq)); + } + WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + err = wl_set_wpa_version(dev, sme); + if (unlikely(err)) + return err; + + err = wl_set_auth_type(dev, sme); + if (unlikely(err)) + return err; + + err = wl_set_set_cipher(dev, sme); + if (unlikely(err)) + return err; + + err = wl_set_key_mgmt(dev, sme); + if (unlikely(err)) + return err; + + err = wl_set_set_sharedkey(dev, sme); + if (unlikely(err)) + return err; + + wl_update_prof(wl, NULL, sme->bssid, WL_PROF_BSSID); + /* + * Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); + + join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); + memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); + join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); + wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID); + memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + + wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); + WL_DBG(("join_param_size %d\n", join_params_size)); + + if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { + WL_ERR(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, + join_params.ssid.SSID_len)); + } + err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + set_bit(WL_STATUS_CONNECTING, &wl->status); + + return err; +} + +static s32 +wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct wl_priv *wl = WL_PRIV_GET(); + scb_val_t scbval; + bool act = false; + s32 err = 0; + + WL_ERR(("Reason %d\n\n\n", reason_code)); + CHECK_SYS_UP(); + act = *(bool *) wl_read_prof(wl, WL_PROF_ACT); + if (likely(act)) { + scbval.val = reason_code; + memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + } + + return err; +} + +static s32 +wl_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm) +{ + + struct wl_priv *wl = WL_PRIV_GET(); + struct net_device *ndev = wl_to_prmry_ndev(wl); + u16 txpwrmw; + s32 err = 0; + s32 disable = 0; + + CHECK_SYS_UP(); + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + break; + case NL80211_TX_POWER_LIMITED: + if (dbm < 0) { + WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); + return -EINVAL; + } + break; + case NL80211_TX_POWER_FIXED: + if (dbm < 0) { + WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); + return -EINVAL; + } + break; + } + /* Make sure radio is off or on as far as software is concerned */ + disable = WL_RADIO_SW_DISABLE << 16; + disable = htod32(disable); + err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); + return err; + } + + if (dbm > 0xffff) + txpwrmw = 0xffff; + else + txpwrmw = (u16) dbm; + err = wl_dev_intvar_set(ndev, "qtxpower", + (s32) (bcm_mw_to_qdbm(txpwrmw))); + if (unlikely(err)) { + WL_ERR(("qtxpower error (%d)\n", err)); + return err; + } + wl->conf->tx_power = dbm; + + return err; +} + +static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct net_device *ndev = wl_to_prmry_ndev(wl); + s32 txpwrdbm; + u8 result; + s32 err = 0; + + CHECK_SYS_UP(); + err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); + *dbm = (s32) bcm_qdbm_to_mw(result); + + return err; +} + +#ifdef NEW_COMPAT_WIRELESS +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx, bool unicast, bool multicast) +#else +static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_idx) +#endif /* NEW_COMPAT_WIRELESS */ +{ + struct wl_priv *wl = WL_PRIV_GET(); + u32 index; + s32 wsec; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + WL_DBG(("key index (%d)\n", key_idx)); + CHECK_SYS_UP(); + /* TODO: wl_cfgp2p_bssiovar_get seems to have a problem here + * roll back to old way + err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + */ + UNUSED_PARAMETER(bssidx); + err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + wsec = dtoh32(wsec); + if (wsec & WEP_ENABLED) { + /* Just select a new current key */ + index = (u32) key_idx; + index = htod32(index); + err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, + sizeof(index)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + } + } + return err; +} + +static s32 +wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, const u8 *mac_addr, struct key_params *params) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_wsec_key key; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + memset(&key, 0, sizeof(key)); + key.index = (u32) key_idx; + + if (!ETHER_ISMULTI(mac_addr)) + memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + key.len = (u32) params->key_len; + + /* check for key index change */ + if (key.len == 0) { + /* key delete */ + swap_key_from_BE(&key); + wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + if (unlikely(err)) { + WL_ERR(("key delete error (%d)\n", err)); + return err; + } + } else { + if (key.len > sizeof(key.data)) { + WL_ERR(("Invalid key length (%d)\n", key.len)); + return -EINVAL; + } + + WL_DBG(("Setting the key index %d\n", key.index)); + memcpy(key.data, params->key, key.len); + + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { + u8 keybuf[8]; + memcpy(keybuf, &key.data[24], sizeof(keybuf)); + memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); + memcpy(&key.data[16], keybuf, sizeof(keybuf)); + } + + /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ + if (params->seq && params->seq_len == 6) { + /* rx iv */ + u8 *ivptr; + ivptr = (u8 *) params->seq; + key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key.iv_initialized = true; + } + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + swap_key_from_BE(&key); +#ifdef CONFIG_WIRELESS_EXT + dhd_wait_pend8021x(dev); +#endif + wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } + } + return err; +} + +static s32 +wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct wl_wsec_key key; + s32 val = 0; + s32 wsec = 0; + s32 err = 0; + uint8 keybuf[8]; + s32 bssidx = 0; + struct wl_priv *wl = WL_PRIV_GET(); + + WL_DBG(("key index (%d)\n", key_idx)); + CHECK_SYS_UP(); + + bssidx = wl_cfgp2p_find_idx(wl, dev); + + if (mac_addr) { +#if defined(P2P_CONFLICT_GONE) + wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); + goto exit; +#else + return wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); +#endif /* defined(P2P_CONFLICT_GONE) */ + } + memset(&key, 0, sizeof(key)); + + key.len = (u32) params->key_len; + key.index = (u32) key_idx; + + if (unlikely(key.len > sizeof(key.data))) { + WL_ERR(("Too long key length (%u)\n", key.len)); + return -EINVAL; + } + memcpy(key.data, params->key, key.len); + + key.flags = WL_PRIMARY_KEY; + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + val = WEP_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + val = TKIP_ENABLED; + /* wpa_supplicant switches the third and fourth quarters of the TKIP key, linm */ + bcopy(&key.data[24], keybuf, sizeof(keybuf)); + bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); + bcopy(keybuf, &key.data[16], sizeof(keybuf)); + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + val = AES_ENABLED; + WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + break; + default: + WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + return -EINVAL; + } + + /* Set the new key/index */ + swap_key_from_BE(&key); + err = wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + return err; + } +#if defined(P2P_CONFLICT_GONE) +exit: +#endif + val = WEP_ENABLED; + err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + if (unlikely(err)) { + WL_ERR(("get wsec error (%d)\n", err)); + return err; + } + wsec &= ~(WEP_ENABLED); + wsec |= val; + err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); + if (unlikely(err)) { + WL_ERR(("set wsec error (%d)\n", err)); + return err; + } + +#ifdef NOT_YET + /* TODO: Removed in P2P, check later --lm */ + val = 1; /* assume shared key. otherwise 0 */ + val = htod32(val); + err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); + return err; + } +#endif + return err; +} + +static s32 +wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr) +{ + struct wl_wsec_key key; + struct wl_priv *wl = WL_PRIV_GET(); + s32 err = 0; + s32 val; + s32 wsec = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + WL_DBG(("Enter\n")); + CHECK_SYS_UP(); + memset(&key, 0, sizeof(key)); + + key.index = (u32) key_idx; + key.flags = WL_PRIMARY_KEY; + key.algo = CRYPTO_ALGO_OFF; + + WL_DBG(("key index (%d)\n", key_idx)); + /* Set the new key/index */ + swap_key_from_BE(&key); + wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + if (unlikely(err)) { + if (err == -EINVAL) { + if (key.index >= DOT11_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + WL_DBG(("invalid key index (%d)\n", key_idx)); + } + } else { + WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + } + return err; + } + + val = 0; + err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + if (unlikely(err)) { + WL_ERR(("get wsec error (%d)\n", err)); + return err; + } + + wsec &= ~(WEP_ENABLED); + wsec |= val; + err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); + if (unlikely(err)) { + WL_ERR(("set wsec error (%d)\n", err)); + return err; + } + +#ifdef NOT_YET + /* TODO: Removed in P2P twig, check later --lin */ + val = 0; /* assume open key. otherwise 1 */ + val = htod32(val); + err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); + return err; + } +#endif + return err; +} + +static s32 +wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +{ + struct key_params params; + struct wl_wsec_key key; + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_security *sec; + s32 wsec; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + WL_DBG(("key index (%d)\n", key_idx)); + CHECK_SYS_UP(); + memset(&key, 0, sizeof(key)); + key.index = key_idx; + swap_key_to_BE(&key); + memset(¶ms, 0, sizeof(params)); + params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); + memcpy(params.key, key.data, params.key_len); + + wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + if (unlikely(err)) { + WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + return err; + } + wsec = dtoh32(wsec); + switch (wsec) { + case WEP_ENABLED: + sec = wl_read_prof(wl, WL_PROF_SEC); + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + default: + WL_ERR(("Invalid algo (0x%x)\n", wsec)); + return -EINVAL; + } + + callback(cookie, ¶ms); + return err; +} + +static s32 +wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, u8 key_idx) +{ + WL_INFO(("Not supported\n")); + CHECK_SYS_UP(); + return -EOPNOTSUPP; +} + +static s32 +wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct wl_priv *wl = WL_PRIV_GET(); + scb_val_t scb_val; + int rssi; + s32 rate; + s32 err = 0; + + CHECK_SYS_UP(); + if (unlikely + (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) { + WL_ERR(("Wrong Mac address\n")); + return -ENOENT; + } + + /* Report the current tx rate */ + err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); + } + + if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t)); + if (unlikely(err)) { + WL_ERR(("Could not get rssi (%d)\n", err)); + return err; + } + rssi = dtoh32(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); + } + +#if defined(ANDROID_WIRELESS_PATCH) + err = wl_dev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed)); + sinfo->link_speed = sinfo->link_speed / 2; /* Convert internal 500Kbps to Mpbs */ + if (!err) + sinfo->filled |= STATION_LINK_SPEED; + else + WL_ERR(("WLC_GET_RATE failed\n")); +#endif + + return err; +} + +static s32 +wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, s32 timeout) +{ + s32 pm; + s32 err = 0; + + CHECK_SYS_UP(); + pm = enabled ? PM_FAST : PM_OFF; + pm = htod32(pm); + WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); + err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); + if (unlikely(err)) { + if (err == -ENODEV) + WL_DBG(("net_device is not ready yet\n")); + else + WL_ERR(("error (%d)\n", err)); + return err; + } + return err; +} + +static __used u32 wl_find_msb(u16 bit16) +{ + u32 ret = 0; + + if (bit16 & 0xff00) { + ret += 8; + bit16 >>= 8; + } + + if (bit16 & 0xf0) { + ret += 4; + bit16 >>= 4; + } + + if (bit16 & 0xc) { + ret += 2; + bit16 >>= 2; + } + + if (bit16 & 2) + ret += bit16 & 2; + else if (bit16) + ret += bit16; + + return ret; +} + +static s32 +wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct wl_rateset rateset; + s32 rate; + s32 val; + s32 err_bg; + s32 err_a; + u32 legacy; + s32 err = 0; + + CHECK_SYS_UP(); + /* addr param is always NULL. ignore it */ + /* Get current rateset */ + err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, + sizeof(rateset)); + if (unlikely(err)) { + WL_ERR(("could not get current rateset (%d)\n", err)); + return err; + } + + rateset.count = dtoh32(rateset.count); + + legacy = wl_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy); + if (!legacy) + legacy = wl_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy); + + val = wl_g_rates[legacy - 1].bitrate * 100000; + + if (val < rateset.count) { + /* Select rate by rateset index */ + rate = rateset.rates[val] & 0x7f; + } else { + /* Specified rate in bps */ + rate = val / 500000; + } + + WL_DBG(("rate %d mbps\n", (rate / 2))); + + /* + * + * Set rate override, + * Since the is a/b/g-blind, both a/bg_rate are enforced. + */ + err_bg = wl_dev_intvar_set(dev, "bg_rate", rate); + err_a = wl_dev_intvar_set(dev, "a_rate", rate); + if (unlikely(err_bg && err_a)) { + WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a)); + return err_bg | err_a; + } + + return err; +} + +static s32 wl_cfg80211_resume(struct wiphy *wiphy) +{ + s32 err = 0; + + CHECK_SYS_UP(); + wl_invoke_iscan(WL_PRIV_GET()); + + return err; +} + +static s32 wl_cfg80211_suspend(struct wiphy *wiphy) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct net_device *ndev = wl_to_prmry_ndev(wl); + s32 err = 0; + + CHECK_SYS_UP(); + + set_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + wl_term_iscan(wl); + if (wl->scan_request) { + cfg80211_scan_done(wl->scan_request, true); + wl_set_mpc(ndev, 1); + wl->scan_request = NULL; + } + clear_bit(WL_STATUS_SCANNING, &wl->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + + return err; +} + +static __used s32 +wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, + s32 err) +{ + int i, j; + + WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); + for (i = 0; i < pmk_list->pmkids.npmkid; i++) { + WL_DBG(("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID)); + for (j = 0; j < WPA2_PMKID_LEN; j++) { + WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); + } + } + if (likely(!err)) { + err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list, + sizeof(*pmk_list)); + } + + return err; +} + +static s32 +wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct wl_priv *wl = WL_PRIV_GET(); + s32 err = 0; + int i; + + CHECK_SYS_UP(); + for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) + if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + if (i < WL_NUM_PMKIDS_MAX) { + memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, + ETHER_ADDR_LEN); + memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, + WPA2_PMKID_LEN); + if (i == wl->pmk_list->pmkids.npmkid) + wl->pmk_list->pmkids.npmkid++; + } else { + err = -EINVAL; + } + WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", + wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid]. + PMKID[i])); + } + + err = wl_update_pmklist(dev, wl->pmk_list, err); + + return err; +} + +static s32 +wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct wl_priv *wl = WL_PRIV_GET(); + struct _pmkid_list pmkid; + s32 err = 0; + int i; + + CHECK_SYS_UP(); + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); + + WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID)); + for (i = 0; i < WPA2_PMKID_LEN; i++) { + WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); + } + + for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) + if (!memcmp + (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + + if ((wl->pmk_list->pmkids.npmkid > 0) && + (i < wl->pmk_list->pmkids.npmkid)) { + memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); + for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { + memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, + &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, + ETHER_ADDR_LEN); + memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, + &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, + WPA2_PMKID_LEN); + } + wl->pmk_list->pmkids.npmkid--; + } else { + err = -EINVAL; + } + + err = wl_update_pmklist(dev, wl->pmk_list, err); + + return err; + +} + +static s32 +wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_priv *wl = WL_PRIV_GET(); + s32 err = 0; + + CHECK_SYS_UP(); + memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); + err = wl_update_pmklist(dev, wl->pmk_list, err); + return err; + +} + +wl_scan_params_t * +wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) +{ + wl_scan_params_t *params; + int params_size; + int num_chans; + + *out_params_size = 0; + + /* Our scan params only need space for 1 channel and 0 ssids */ + params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); + params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + WL_ERR(("%s: mem alloc failed (%d bytes)\n", __func__, params_size)); + return params; + } + memset(params, 0, params_size); + params->nprobes = nprobes; + + num_chans = (channel == 0) ? 0 : 1; + + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + params->bss_type = DOT11_BSSTYPE_ANY; + params->scan_type = DOT11_SCANTYPE_ACTIVE; + params->nprobes = htod32(1); + params->active_time = htod32(-1); + params->passive_time = htod32(-1); + params->home_time = htod32(10); + params->channel_list[0] = htodchanspec(channel); + + /* Our scan params have 1 channel and 0 ssids */ + params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + *out_params_size = params_size; /* rtn size to the caller */ + return params; +} +s32 +wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) +{ + wl_scan_params_t *params; + s32 params_size; + s32 err = BCME_OK; + + WL_DBG(("Enter\n")); + + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } + /* Do a scan abort to stop the driver's scan engine */ + err = wl_dev_ioctl(ndev, WLC_SCAN, params, params_size); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + clear_bit(WL_STATUS_SCANNING, &wl->status); + + if (wl->p2p_on && test_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status)) + clear_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status); + return err; +} +static s32 +wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel * channel, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 *cookie) +{ + s32 target_channel; + + s32 err = BCME_OK; + struct wl_priv *wl = WL_PRIV_GET(); + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); + if (likely(test_bit(WL_STATUS_SCANNING, &wl->status))) { + wl_cfg80211_scan_abort(wl, dev); + } + + target_channel = ieee80211_frequency_to_channel(channel->center_freq); + memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); + wl->remain_on_chan_type = channel_type; + wl->cache_cookie = *cookie; + cfg80211_ready_on_channel(dev, *cookie, channel, + channel_type, duration, GFP_KERNEL); + if (!wl->p2p_on) { + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p_dev_addr, &wl->p2p_int_addr); + + /* In case of p2p_listen command, supplicant send remain_on_channel + * without turning on P2P + */ + + err = wl_cfgp2p_enable_discovery(wl, NULL, 0); + + if (unlikely(err)) { + goto exit; + } + wl->p2p_on = true; + } + if (wl->p2p_on) + wl_cfgp2p_discover_listen(wl, target_channel, duration); + + +exit: + return err; +} + +static s32 +wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, u64 cookie) +{ + + s32 err = 0; + WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); + + + return err; +} + +static s32 +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *channel, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8* buf, size_t len, u64 *cookie) +{ + wl_action_frame_t *action_frame; + wl_af_params_t *af_params; + wifi_p2p_ie_t *p2p_ie; + wpa_ie_fixed_t *wps_ie; + const struct ieee80211_mgmt *mgmt; + struct wl_priv *wl = WL_PRIV_GET(); + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + s32 err = BCME_OK; + s32 bssidx = 0; + u32 p2pie_len = 0; + u32 wpsie_len = 0; + u16 fc; + WL_DBG(("Enter \n")); + /* find bssidx based on ndev */ + bssidx = wl_cfgp2p_find_idx(wl, dev); + + if (bssidx == -1) { + + WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); + return -ENODEV; + } + if (wl->p2p_on) { + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p_dev_addr, &wl->p2p_int_addr); + + /* Suspend P2P discovery search-listen to prevent it from changing the + * channel. + */ + wl_cfgp2p_discover_enable_search(wl, FALSE); + } + mgmt = (const struct ieee80211_mgmt *) buf; + fc = mgmt->frame_control; + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_ASSOC_REQ: + WL_DBG(("packet type: IEEE80211_STYPE_ASSOC_REQ, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_ASSOC_RESP: + WL_DBG(("packet type: IEEE80211_STYPE_ASSOC_RESP, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_REASSOC_REQ: + WL_DBG(("packet type: IEEE80211_STYPE_REASSOC_REQ, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_REASSOC_RESP: + WL_DBG(("packet type: IEEE80211_STYPE_REASSOC_RESP, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_PROBE_REQ: + WL_DBG(("packet type: IEEE80211_STYPE_PROBE_REQ, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_PROBE_RESP: + WL_DBG(("packet type: IEEE80211_STYPE_PROBE_RESP, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_BEACON: + WL_DBG(("packet type: IEEE80211_STYPE_BEACON, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_ATIM: + WL_DBG(("packet type: IEEE80211_STYPE_ATIM, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_DISASSOC: + WL_DBG(("packet type: IEEE80211_STYPE_DISASSOC, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_AUTH: + WL_DBG(("packet type: IEEE80211_STYPE_AUTH, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_DEAUTH: + WL_DBG(("packet type: IEEE80211_STYPE_DEAUTH, bssidx : %d\n", bssidx)); + break; + case IEEE80211_STYPE_ACTION: + WL_DBG(("packet type: IEEE80211_STYPE_ACTION, bssidx : %d\n", bssidx)); + break; + } + if (fc != IEEE80211_STYPE_ACTION) { + if (wl->p2p_on && (fc == IEEE80211_STYPE_PROBE_RESP)) { + s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + s32 ie_len = len - ie_offset; + if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len)) + != NULL) { + /* Total length of P2P Information Element */ + p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); + /* Have to change p2p device address in dev_info attribute + * because Supplicant use primary eth0 address + */ + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, + &wl->p2p_dev_addr, P2P_SEID_DEV_INFO); + } + if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len)) + != NULL) { + /* Order of Vendor IE is 1) WPS IE + + * 2) P2P IE created by supplicant + * So, it is ok to find start address of WPS IE + * to save IEs to firmware + */ + wpsie_len = wps_ie->length + sizeof(wps_ie->length) + + sizeof(wps_ie->tag); + wl_cfgp2p_set_managment_ie(wl, dev, bssidx, + VNDR_IE_PRBRSP_FLAG, + (u8 *)wps_ie, wpsie_len + p2pie_len); + + } + } + cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL); + + goto exit; + } + af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); + + if (af_params == NULL) + { + WL_ERR(("unable to allocate frame\n")); + return -ENOMEM; + } + + action_frame = &af_params->action_frame; + + /* Add the packet Id */ + action_frame->packetId = (u32) action_frame; + WL_DBG(("action frame %d\n", action_frame->packetId)); + /* Add BSSID */ + memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); + memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); + + /* Add the length exepted for 802.11 header */ + action_frame->len = len - DOT11_MGMT_HDR_LEN; + WL_DBG(("action_frame->len: %d\n", action_frame->len)); + + /* Add the channel */ + af_params->channel = + ieee80211_frequency_to_channel(channel->center_freq); + + /* Add the dwell time + * Dwell time to stay off-channel to wait for a response action frame + * after transmitting an GO Negotiation action frame + */ + af_params->dwell_time = 200; + + memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); + + if (wl->p2p_vif_created) { + wifi_p2p_pub_act_frame_t *act_frm = + (wifi_p2p_pub_act_frame_t *) (action_frame->data); + /* + * Have to change intented address from GO REQ or GO RSP + * because wpa-supplicant use eth0 primary address + */ + if (act_frm->subtype == P2P_PAF_GON_REQ || act_frm->subtype == P2P_PAF_GON_RSP) { + p2p_ie = wl_cfgp2p_find_p2pie(act_frm->elts, + action_frame->len - P2P_PUB_AF_FIXED_LEN); + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_int_addr, + P2P_SEID_INTINTADDR); + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, + P2P_SEID_DEV_INFO); + } + } + + err = wl_cfgp2p_tx_action_frame(wl, af_params, bssidx); + cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL); + + kfree(af_params); +exit: + return err; +} + + +static void +wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, + u16 frame_type, bool reg) +{ + + WL_DBG(("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg)); + + if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) + return; + + return; +} + + +static s32 +wl_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + if (params->use_cts_prot >= 0) { + } + + if (params->use_short_preamble >= 0) { + } + + if (params->use_short_slot_time >= 0) { + } + + if (params->basic_rates) { + } + + if (params->ap_isolate >= 0) { + } + + if (params->ht_opmode >= 0) { + } + + return 0; +} + +static s32 +wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + s32 channel; + s32 err = BCME_OK; + + channel = ieee80211_frequency_to_channel(chan->center_freq); + WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", + dev->ifindex, channel_type, channel)); + wl_dev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)); + + return err; +} + +static s32 +wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) +{ + s32 len = wpa2ie->len; + s32 err = BCME_OK; + u16 auth = 0; /* d11 open authentication */ + u16 wpa_auth = 0; + u16 count; + u32 wsec; + u32 pval; + u32 gval; + u8* tmp; + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + if (wpa2ie == NULL) + goto exit; + /* check the mcast cipher */ + mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; + tmp = mcast->oui; + switch (tmp[DOT11_OUI_LEN]) { + case WPA_CIPHER_NONE: + gval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + gval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + gval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + gval = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + break; + } + len -= WPA_SUITE_LEN; + /* check the unicast cipher */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + count = ltoh16_ua(&ucast->count); + tmp = ucast->list[0].oui; + switch (tmp[DOT11_OUI_LEN]) { + case WPA_CIPHER_NONE: + pval = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + pval = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + pval = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + pval = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + break; + } + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* check the AKM */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1]; + count = ltoh16_ua(&mgmt->count); + tmp = (u8 *)&mgmt->list[0]; + switch (tmp[DOT11_OUI_LEN]) { + case RSN_AKM_NONE: + wpa_auth = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + wpa_auth = WPA2_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + wpa_auth = WPA2_AUTH_PSK; + break; + default: + WL_ERR(("No Key Mgmt Info\n")); + break; + } + /* set auth */ + err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, auth); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + } + /* set wsec */ + err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + } + /* set upper-layer auth */ + err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, wpa_auth); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + } +exit: + return 0; +} + +static s32 +wl_check_wpaie(struct net_device *dev, bcm_tlv_t *wpaie, s32 bssidx) +{ + if (wpaie == NULL) + goto exit; + +exit: + return 0; +} + +static s32 +wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + s32 err = BCME_OK; + bcm_tlv_t *ssid_ie; + wpa_ie_fixed_t *wps_ie; + wpa_ie_fixed_t *wpa_ie; + bcm_tlv_t *wpa2_ie; + wifi_p2p_ie_t *p2p_ie; + struct wl_priv *wl = WL_PRIV_GET(); + bool is_bssup = false; + u16 wpsie_len = 0; + u16 p2pie_len = 0; + u8 beacon_ie[IE_MAX_LEN]; + s32 ie_offset = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 infra = 1; + + memset(beacon_ie, 0, sizeof(beacon_ie)); + + WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", + info->interval, info->dtim_period, info->head_len, info->tail_len)); + if (wl->p2p_on && (bssidx >= wl_to_p2p_bss_bssidx(wl, + P2PAPI_BSSCFG_CONNECTION))) { + /* We don't need to set beacon for P2P_GO, + * but need to parse ssid from beacon_parameters + * because there is no way to set ssid + */ + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + memcpy(wl->p2p_ssid.SSID, ssid_ie->data, ssid_ie->len); + wl->p2p_ssid.SSID_len = ssid_ie->len; + WL_DBG(("SSID (%s) in Head \n", ssid_ie->data)); + + } else { + WL_ERR(("No SSID in beacon \n")); + } + + /* find the WPSIE */ + if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { + wpsie_len = wps_ie->length + sizeof(wps_ie->tag) + sizeof(wps_ie->length); + /* + * Should be compared with saved ie before saving it + */ + if (wl_dbg_level & WL_DBG_INFO) + wl_dbg_dump_wps_ie((char *) wps_ie); + memcpy(beacon_ie, wps_ie, wpsie_len); + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + + + /* find the P2PIE */ + if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) { + /* Total length of P2P Information Element */ + p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); + /* Have to change device address in dev_id attribute because Supplicant + * use primary eth0 address + */ + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID); + memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len); + + } else { + WL_ERR(("No P2PIE in beacon \n")); + } + wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, + beacon_ie, wpsie_len + p2pie_len); + wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG, + beacon_ie, wpsie_len + p2pie_len); + /* find the WPA_IE */ + if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail, info->tail_len)) != NULL) { + WL_DBG((" WPA IE is found\n")); + } + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); + + if (!is_bssup && (wpa_ie != NULL || wpa2_ie != NULL)) { + wl_check_wpa2ie(dev, wpa2_ie, bssidx); + wl_check_wpaie(dev, (bcm_tlv_t *)wpa_ie, bssidx); + + err = wl_dev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32)); + if (err < 0) { + WL_ERR(("SET INFRA error %d\n", err)); + } + + err = wl_cfgp2p_bssiovar_set(dev, "ssid", bssidx, &wl->p2p_ssid, + sizeof(wl->p2p_ssid)); + + wl_cfgp2p_bss(dev, bssidx, 1); + } + } + return 0; +} + +#if defined(ANDROID_WIRELESS_PATCH) +static s32 +wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev) +{ + /* struct wl_priv *wl = wiphy_to_wl(wiphy); */ + s32 err = 0; + + printk("Android driver start command\n"); + return err; +} + +static s32 +wl_cfg80211_drv_stop(struct wiphy *wiphy, struct net_device *dev) +{ + /* struct wl_priv *wl = wiphy_to_wl(wiphy); */ + s32 err = 0; + + printk("Android driver stop command\n"); + return err; +} +#endif /* defined(ANDROID_WIRELESS_PATCH) */ + +static struct cfg80211_ops wl_cfg80211_ops = { + .add_virtual_intf = wl_cfg80211_add_virtual_iface, + .del_virtual_intf = wl_cfg80211_del_virtual_iface, + .change_virtual_intf = wl_cfg80211_change_virtual_iface, + .scan = wl_cfg80211_scan, + .set_wiphy_params = wl_cfg80211_set_wiphy_params, + .join_ibss = wl_cfg80211_join_ibss, + .leave_ibss = wl_cfg80211_leave_ibss, + .get_station = wl_cfg80211_get_station, + .set_tx_power = wl_cfg80211_set_tx_power, + .get_tx_power = wl_cfg80211_get_tx_power, + .add_key = wl_cfg80211_add_key, + .del_key = wl_cfg80211_del_key, + .get_key = wl_cfg80211_get_key, + .set_default_key = wl_cfg80211_config_default_key, + .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, + .set_power_mgmt = wl_cfg80211_set_power_mgmt, + .set_bitrate_mask = wl_cfg80211_set_bitrate_mask, + .connect = wl_cfg80211_connect, + .disconnect = wl_cfg80211_disconnect, + .suspend = wl_cfg80211_suspend, + .resume = wl_cfg80211_resume, + .set_pmksa = wl_cfg80211_set_pmksa, + .del_pmksa = wl_cfg80211_del_pmksa, + .flush_pmksa = wl_cfg80211_flush_pmksa, + .remain_on_channel = wl_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wl_cfg80211_mgmt_tx, + .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, + .change_bss = wl_cfg80211_change_bss, + .set_channel = wl_cfg80211_set_channel, + .set_beacon = wl_cfg80211_set_beacon, +#if defined(ANDROID_WIRELESS_PATCH) + .drv_start = wl_cfg80211_drv_start, + .drv_stop = wl_cfg80211_drv_stop, +#endif +}; + +static s32 wl_mode_to_nl80211_iftype(s32 mode) +{ + s32 err = 0; + + switch (mode) { + case WL_MODE_BSS: + return NL80211_IFTYPE_STATION; + case WL_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; + case WL_MODE_AP: + return NL80211_IFTYPE_AP; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return err; +} + +static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, + struct device *dev) +{ + struct wireless_dev *wdev; + s32 err = 0; + struct wl_priv *wl; + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return ERR_PTR(-ENOMEM); + } + wdev->wiphy = + wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface); + if (unlikely(!wdev->wiphy)) { + WL_ERR(("Couldn not allocate wiphy device\n")); + err = -ENOMEM; + goto wiphy_new_out; + } + set_wiphy_dev(wdev->wiphy, dev); + wl = wiphy_to_wl(wdev->wiphy); + wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; + wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | + (BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = __wl_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); +#ifdef NEW_COMPAT_WIRELESS + wdev->wiphy->max_remain_on_channel_duration = 5000; +#endif + wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; +#ifndef WL_POWERSAVE_DISABLED + wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#else + wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif /* !WL_POWERSAVE_DISABLED */ + + err = wiphy_register(wdev->wiphy); + if (unlikely(err < 0)) { + WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + goto wiphy_register_out; + } + return wdev; + +wiphy_register_out: + wiphy_free(wdev->wiphy); + +wiphy_new_out: + kfree(wdev); + + return ERR_PTR(err); +} + +static void wl_free_wdev(struct wl_priv *wl) +{ + int i; + struct wireless_dev *wdev = wl_to_wdev(wl); + + if (unlikely(!wdev)) { + WL_ERR(("wdev is invalid\n")); + return; + } + + for (i = 0; i < VWDEV_CNT; i++) { + if ((wl->vwdev[i] != NULL)) { + kfree(wl->vwdev[i]); + wl->vwdev[i] = NULL; + } + } + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); + wl_to_wdev(wl) = NULL; +} + +static s32 wl_inform_bss(struct wl_priv *wl) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; /* must be initialized */ + s32 err = 0; + s32 i; + + bss_list = wl->bss_list; + if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) { + WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version)); + return -EOPNOTSUPP; + } + WL_DBG(("scanned AP count (%d)\n", bss_list->count)); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + err = wl_inform_single_bss(wl, bi); + if (unlikely(err)) + break; + } + return err; +} + +static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) +{ + struct wiphy *wiphy = wl_to_wiphy(wl); + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + struct wl_cfg80211_bss_info *notif_bss_info; + struct wl_scan_req *sr = wl_to_sr(wl); + struct beacon_proberesp *beacon_proberesp; + s32 mgmt_type; + u32 signal; + u32 freq; + s32 err = 0; + + if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { + WL_DBG(("Beacon is larger than buffer. Discarding\n")); + return err; + } + notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) + - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL); + if (unlikely(!notif_bss_info)) { + WL_ERR(("notif_bss_info alloc failed\n")); + return -ENOMEM; + } + mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; + notif_bss_info->channel = + bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec); + + if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + notif_bss_info->rssi = bi->RSSI; + memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); + mgmt_type = wl->active_scan ? + IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; + if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); + } + beacon_proberesp = wl->active_scan ? + (struct beacon_proberesp *)&mgmt->u.probe_resp : + (struct beacon_proberesp *)&mgmt->u.beacon; + beacon_proberesp->timestamp = 0; + beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); + beacon_proberesp->capab_info = cpu_to_le16(bi->capability); + wl_rst_ie(wl); + /* + * wl_add_ie is not necessary because it can only add duplicated + * SSID, rate information to frame_buf + */ + /* + * wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID); + * wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count, + * bi->rateset.rates); + */ + wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); + wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - + offsetof(struct wl_cfg80211_bss_info, frame_buf)); + notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, + u.beacon.variable) + wl_get_ielen(wl); + freq = ieee80211_channel_to_frequency(notif_bss_info->channel); + channel = ieee80211_get_channel(wiphy, freq); + + WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", + bi->SSID, + notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID)); + + signal = notif_bss_info->rssi * 100; + if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu + (notif_bss_info->frame_len), + signal, GFP_KERNEL))) { + WL_ERR(("cfg80211_inform_bss_frame error\n")); + kfree(notif_bss_info); + return -EINVAL; + } + kfree(notif_bss_info); + + return err; +} + +static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e) +{ + /* To SK, chagne NOT_YET to 1 if you don't like this + * But in general WLC_E_SET_SSID is more reliable --lin + */ +#ifdef NOT_YET + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + + if (event == WLC_E_LINK) { + if (flags & WLC_EVENT_MSG_LINK) { + if (wl_is_ibssmode(wl)) { + if (wl_is_ibssstarter(wl)) { + } + } else { + return true; + } + } + } + return false; +#else + u32 event = ntoh32(e->event_type); + uint32 status = ntoh32(e->status); + + WL_DBG(("event %d\n", event)); + /* was WLC_E_LINK here, changed as WLC_E_SET_SSID is more reliable -- lin */ + if (event == WLC_E_SET_SSID) { + if (status == WLC_E_STATUS_SUCCESS) { + if (!wl_is_ibssmode(wl)) + return true; + } + } + + WL_DBG(("wl_is_linkup false\n")); + return false; +#endif /* NOT_YET */ +} + +static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u16 flags = ntoh16(e->flags); + + if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) { + return true; + } else if (event == WLC_E_LINK) { + if (!(flags & WLC_EVENT_MSG_LINK)) + return true; + } + + return false; +} + +static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + + if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) + return true; + if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) + return true; + + return false; +} + +static bool wl_is_newsta(struct wl_priv *wl, const wl_event_msg_t *e) +{ + u32 event = ntoh32(e->event_type); + u32 status = ntoh32(e->status); + + if (event == WLC_E_ASSOC_IND && (status == WLC_E_STATUS_SUCCESS)) { + return true; + } + return false; +} + +static s32 +wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + bool act; + s32 err = 0; + u8 body[200]; + + WL_DBG(("Enter \n")); + + if (wl->conf->mode == WL_MODE_AP) { + if (wl_is_newsta(wl, e)) { + u32 len = ntoh32(e->datalen); + memcpy(body, e->addr.octet, ETHER_ADDR_LEN); + memcpy(&body[ETHER_ADDR_LEN], data, len); + cfg80211_send_rx_assoc(ndev, body, len + ETHER_ADDR_LEN); + } + } else { + WL_ERR(("event %d ", ntoh32(e->event_type))); + if (wl_is_linkup(wl, e)) { + wl_link_up(wl); + if (wl_is_ibssmode(wl)) { + printk("cfg80211_ibss_joined"); + cfg80211_ibss_joined(ndev, (s8 *)&e->addr, + GFP_KERNEL); + WL_DBG(("joined in IBSS network\n")); + } else { + printk("wl_bss_connect_done succeeded"); + wl_bss_connect_done(wl, ndev, e, data, true); + WL_DBG(("joined in BSS network \"%s\"\n", + ((struct wlc_ssid *) + wl_read_prof(wl, WL_PROF_SSID))->SSID)); + } + act = true; + wl_update_prof(wl, e, &act, WL_PROF_ACT); + } else if (wl_is_linkdown(wl, e)) { + if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { + printk("link down, call cfg80211_disconnected"); + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl_link_down(wl); + wl_init_prof(wl->profile); + } + } else if (wl_is_nonetwork(wl, e)) { + printk("connect failed wl->status 0x%x", (int)wl->status); + if (test_bit(WL_STATUS_CONNECTING, &wl->status)) + wl_bss_connect_done(wl, ndev, e, data, false); + } else { + printk("nothing"); + } + printk("\n"); + } + return err; +} + +static s32 +wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + bool act; + s32 err = 0; + + WL_DBG(("Enter \n")); + wl_bss_roaming_done(wl, ndev, e, data); + act = true; + wl_update_prof(wl, e, &act, WL_PROF_ACT); + + return err; +} + +static __used s32 +wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) +{ + struct wl_priv *wl = WL_PRIV_GET(); + u32 buflen; + + buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX); + BUG_ON(unlikely(!buflen)); + + return wl_dev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen); +} + +static s32 +wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, + s32 buf_len) +{ + struct wl_priv *wl = WL_PRIV_GET(); + u32 len; + s32 err = 0; + + len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX); + BUG_ON(unlikely(!len)); + err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, + WL_IOCTL_LEN_MAX); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + memcpy(buf, wl->ioctl_buf, buf_len); + + return err; +} + +static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) +{ + struct wl_assoc_ielen *assoc_info; + struct wl_connect_info *conn_info = wl_to_conn(wl); + u32 req_len; + u32 resp_len; + s32 err = 0; + + WL_DBG(("Enter \n")); + err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf, + WL_ASSOC_INFO_MAX); + if (unlikely(err)) { + WL_ERR(("could not get assoc info (%d)\n", err)); + return err; + } + assoc_info = (struct wl_assoc_ielen *)wl->extra_buf; + req_len = assoc_info->req_len; + resp_len = assoc_info->resp_len; + if (req_len) { + err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, + WL_ASSOC_INFO_MAX); + if (unlikely(err)) { + WL_ERR(("could not get assoc req (%d)\n", err)); + return err; + } + conn_info->req_ie_len = req_len; + conn_info->req_ie = + kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL); + } else { + conn_info->req_ie_len = 0; + conn_info->req_ie = NULL; + } + if (resp_len) { + err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, + WL_ASSOC_INFO_MAX); + if (unlikely(err)) { + WL_ERR(("could not get assoc resp (%d)\n", err)); + return err; + } + conn_info->resp_ie_len = resp_len; + conn_info->resp_ie = + kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL); + } else { + conn_info->resp_ie_len = 0; + conn_info->resp_ie = NULL; + } + WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, + conn_info->resp_ie_len)); + + return err; +} + +static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, + size_t *join_params_size) +{ + chanspec_t chanspec = 0; + + if (ch != 0) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0]) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + htodchanspec(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = + htod32(join_params->params.chanspec_num); + + WL_DBG(("%s join_params->params.chanspec_list[0]= %X\n", + __FUNCTION__, join_params->params.chanspec_list[0])); + } +} + +static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) +{ + struct cfg80211_bss *bss; + struct wl_bss_info *bi; + struct wlc_ssid *ssid; + struct bcm_tlv *tim; + u16 beacon_interval; + u8 dtim_period; + size_t ie_len; + u8 *ie; + s32 err = 0; + struct wiphy *wiphy; + wiphy = wl_to_wiphy(wl); + + if (wl_is_ibssmode(wl)) + return err; + + ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID); + bss = cfg80211_get_bss(wiphy, NULL, (s8 *)&wl->bssid, + ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + rtnl_lock(); + if (unlikely(!bss)) { + WL_DBG(("Could not find the AP\n")); + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO, + wl->extra_buf, WL_EXTRA_BUF_MAX); + if (unlikely(err)) { + WL_ERR(("Could not get bss info %d\n", err)); + goto update_bss_info_out; + } + bi = (struct wl_bss_info *)(wl->extra_buf + 4); + if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN))) { + err = -EIO; + goto update_bss_info_out; + } + err = wl_inform_single_bss(wl, bi); + if (unlikely(err)) + goto update_bss_info_out; + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + beacon_interval = cpu_to_le16(bi->beacon_period); + } else { + WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); + ie = bss->information_elements; + ie_len = bss->len_information_elements; + beacon_interval = bss->beacon_interval; + cfg80211_put_bss(bss); + } + + tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); + if (tim) { + dtim_period = tim->data[1]; + } else { + /* + * active scan was done so we could not get dtim + * information out of probe response. + * so we speficially query dtim information to dongle. + */ + err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period)); + if (unlikely(err)) { + WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); + goto update_bss_info_out; + } + } + + wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT); + wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + +update_bss_info_out: + rtnl_unlock(); + return err; +} + +static s32 +wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct wl_connect_info *conn_info = wl_to_conn(wl); + s32 err = 0; + + wl_get_assoc_ies(wl, ndev); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl, ndev); + cfg80211_roamed(ndev, + (u8 *)&wl->bssid, + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); + WL_DBG(("Report roaming result\n")); + + set_bit(WL_STATUS_CONNECTED, &wl->status); + + return err; +} + +static s32 +wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, bool completed) +{ + struct wl_connect_info *conn_info = wl_to_conn(wl); + s32 err = 0; + + WL_DBG((" enter\n")); + wl_get_assoc_ies(wl, ndev); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl, ndev); + if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) { + cfg80211_connect_result(ndev, + (u8 *)&wl->bssid, + conn_info->req_ie, + conn_info->req_ie_len, + conn_info->resp_ie, + conn_info->resp_ie_len, + completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, + GFP_KERNEL); + WL_DBG(("Report connect result - connection %s\n", + completed ? "succeeded" : "failed")); + } else { + cfg80211_roamed(ndev, + (u8 *)&wl->bssid, + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, + GFP_KERNEL); + WL_DBG(("Report roaming result\n")); + } + set_bit(WL_STATUS_CONNECTED, &wl->status); + + return err; +} + +static s32 +wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + u16 flags = ntoh16(e->flags); + enum nl80211_key_type key_type; + + rtnl_lock(); + if (flags & WLC_EVENT_MSG_GROUP) + key_type = NL80211_KEYTYPE_GROUP; + else + key_type = NL80211_KEYTYPE_PAIRWISE; + + cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, + NULL, GFP_KERNEL); + rtnl_unlock(); + + return 0; +} + +static s32 +wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + struct channel_info channel_inform; + struct wl_scan_results *bss_list; + u32 len = WL_SCAN_BUF_MAX; + s32 err = 0; + + + WL_DBG(("Enter \n")); + if (wl->iscan_on && wl->iscan_kickstart) + return wl_wakeup_iscan(wl_to_iscan(wl)); + + if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + WL_DBG(("Scan complete while device not scanning\n")); + return -EINVAL; + } + if (unlikely(!wl->scan_request)) { + } + rtnl_lock(); + err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, + sizeof(channel_inform)); + if (unlikely(err)) { + WL_ERR(("scan busy (%d)\n", err)); + goto scan_done_out; + } + channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); + if (unlikely(channel_inform.scan_channel)) { + + WL_DBG(("channel_inform.scan_channel (%d)\n", + channel_inform.scan_channel)); + } + wl->bss_list = wl->scan_results; + bss_list = wl->bss_list; + memset(bss_list, 0, len); + bss_list->buflen = htod32(len); + err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len); + if (unlikely(err)) { + WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); + err = -EINVAL; + goto scan_done_out; + } + bss_list->buflen = dtoh32(bss_list->buflen); + bss_list->version = dtoh32(bss_list->version); + bss_list->count = dtoh32(bss_list->count); + + err = wl_inform_bss(wl); + if (err) + goto scan_done_out; + +scan_done_out: + if (wl->scan_request) { + WL_ERR(("cfg80211_scan_done\n")); + cfg80211_scan_done(wl->scan_request, false); + wl_set_mpc(ndev, 1); + wl->scan_request = NULL; + } + rtnl_unlock(); + return err; +} + +static s32 +wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + + wl_event_rx_frame_data_t *rxframe = + (wl_event_rx_frame_data_t*)data; + + u8 *mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); + + u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK) & 0x0f); + s32 freq = ieee80211_channel_to_frequency(channel); + + + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); + + WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, + mgmt_frame_len, ntoh32(e->datalen), channel, freq)); + return 0; +} + +static void wl_init_conf(struct wl_conf *conf) +{ + WL_DBG(("Enter \n")); + conf->mode = (u32)-1; + conf->frag_threshold = (u32)-1; + conf->rts_threshold = (u32)-1; + conf->retry_short = (u32)-1; + conf->retry_long = (u32)-1; + conf->tx_power = -1; +} + +static void wl_init_prof(struct wl_profile *prof) +{ + memset(prof, 0, sizeof(*prof)); +} + +static void wl_init_event_handler(struct wl_priv *wl) +{ + memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); + + wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + wl->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; + wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; + wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; + wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; + wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; + wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; + wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; + wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; + wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; + wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; + wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; + wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; + wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; + + /* Used to be like this... + el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; + el->handler[WLC_E_JOIN] = wl_notify_connect_status; + el->handler[WLC_E_LINK] = wl_notify_connect_status; + el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; + el->handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; + el->handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; + el->handler[WLC_E_ROAM] = wl_notify_roaming_status; + el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; + el->handler[WLC_E_SET_SSID] = wl_notify_connect_status; + */ +} + +static s32 wl_init_priv_mem(struct wl_priv *wl) +{ + WL_DBG(("Enter \n")); + wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + if (unlikely(!wl->scan_results)) { + WL_ERR(("Scan results alloc failed\n")); + goto init_priv_mem_out; + } + wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); + if (unlikely(!wl->conf)) { + WL_ERR(("wl_conf alloc failed\n")); + goto init_priv_mem_out; + } + wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL); + if (unlikely(!wl->profile)) { + WL_ERR(("wl_profile alloc failed\n")); + goto init_priv_mem_out; + } + wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (unlikely(!wl->bss_info)) { + WL_ERR(("Bss information alloc failed\n")); + goto init_priv_mem_out; + } + wl->scan_req_int = + (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); + if (unlikely(!wl->scan_req_int)) { + WL_ERR(("Scan req alloc failed\n")); + goto init_priv_mem_out; + } + wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + if (unlikely(!wl->ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + wl->escan_ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + if (unlikely(!wl->escan_ioctl_buf)) { + WL_ERR(("Ioctl buf alloc failed\n")); + goto init_priv_mem_out; + } + wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (unlikely(!wl->extra_buf)) { + WL_ERR(("Extra buf alloc failed\n")); + goto init_priv_mem_out; + } + wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL); + if (unlikely(!wl->iscan)) { + WL_ERR(("Iscan buf alloc failed\n")); + goto init_priv_mem_out; + } + wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL); + if (unlikely(!wl->fw)) { + WL_ERR(("fw object alloc failed\n")); + goto init_priv_mem_out; + } + wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); + if (unlikely(!wl->pmk_list)) { + WL_ERR(("pmk list alloc failed\n")); + goto init_priv_mem_out; + } + + return 0; + +init_priv_mem_out: + wl_deinit_priv_mem(wl); + + return -ENOMEM; +} + +static void wl_deinit_priv_mem(struct wl_priv *wl) +{ + kfree(wl->scan_results); + wl->scan_results = NULL; + kfree(wl->bss_info); + wl->bss_info = NULL; + kfree(wl->conf); + wl->conf = NULL; + kfree(wl->profile); + wl->profile = NULL; + kfree(wl->scan_req_int); + wl->scan_req_int = NULL; + kfree(wl->ioctl_buf); + wl->ioctl_buf = NULL; + kfree(wl->escan_ioctl_buf); + wl->escan_ioctl_buf = NULL; + kfree(wl->extra_buf); + wl->extra_buf = NULL; + kfree(wl->iscan); + wl->iscan = NULL; + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->pmk_list); + wl->pmk_list = NULL; +} + +static s32 wl_create_event_handler(struct wl_priv *wl) +{ + WL_DBG(("Enter \n")); + sema_init(&wl->event_sync, 0); + wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler"); + if (IS_ERR(wl->event_tsk)) { + wl->event_tsk = NULL; + WL_ERR(("failed to create event thread\n")); + return -ENOMEM; + } + return 0; +} + +static void wl_destroy_event_handler(struct wl_priv *wl) +{ + if (wl->event_tsk) { + send_sig(SIGTERM, wl->event_tsk, 1); + kthread_stop(wl->event_tsk); + wl->event_tsk = NULL; + } +} + +static void wl_term_iscan(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); + WL_TRACE(("In\n")); + if (wl->iscan_on && iscan->tsk) { + iscan->state = WL_ISCAN_STATE_IDLE; + WL_INFO(("SIGTERM\n")); + send_sig(SIGTERM, iscan->tsk, 1); + printk("kthread_stop\n"); + kthread_stop(iscan->tsk); + iscan->tsk = NULL; + } +} + +static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) +{ + struct wl_priv *wl = iscan_to_wl(iscan); + struct net_device *ndev = wl_to_prmry_ndev(wl); + + WL_DBG(("Enter \n")); + if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + WL_ERR(("Scan complete while device not scanning\n")); + return; + } + if (likely(wl->scan_request)) { + cfg80211_scan_done(wl->scan_request, aborted); + wl_set_mpc(ndev, 1); + wl->scan_request = NULL; + } + wl->iscan_kickstart = false; +} + +static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan) +{ + if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { + WL_DBG(("wake up iscan\n")); + up(&iscan->sync); + return 0; + } + + return -EIO; +} + +static s32 +wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, + struct wl_scan_results **bss_list) +{ + struct wl_iscan_results list; + struct wl_scan_results *results; + struct wl_iscan_results *list_buf; + s32 err = 0; + + WL_DBG(("Enter \n")); + memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); + list_buf = (struct wl_iscan_results *)iscan->scan_buf; + results = &list_buf->results; + results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; + results->version = 0; + results->count = 0; + + memset(&list, 0, sizeof(list)); + list.results.buflen = htod32(WL_ISCAN_BUF_MAX); + err = wl_dev_iovar_getbuf(iscan->dev, "iscanresults", &list, + WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, + WL_ISCAN_BUF_MAX); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + results->count = dtoh32(results->count); + WL_DBG(("results->count = %d\n", results->count)); + WL_DBG(("results->buflen = %d\n", results->buflen)); + *status = dtoh32(list_buf->status); + *bss_list = results; + + return err; +} + +static s32 wl_iscan_done(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + rtnl_lock(); + wl_inform_bss(wl); + wl_notify_iscan_complete(iscan, false); + rtnl_unlock(); + + return err; +} + +static s32 wl_iscan_pending(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl->iscan; + s32 err = 0; + + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 wl_iscan_inprogress(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl->iscan; + s32 err = 0; + + rtnl_lock(); + wl_inform_bss(wl); + wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); + rtnl_unlock(); + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 wl_iscan_aborted(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + rtnl_lock(); + wl_notify_iscan_complete(iscan, true); + rtnl_unlock(); + + return err; +} + +static s32 wl_iscan_thread(void *data) +{ + struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; + struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; + struct wl_priv *wl = iscan_to_wl(iscan); + u32 status; + int err = 0; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + allow_signal(SIGTERM); + status = WL_SCAN_RESULTS_PARTIAL; + while (likely(!down_interruptible(&iscan->sync))) { + if (kthread_should_stop()) + break; + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + rtnl_lock(); + err = wl_get_iscan_results(iscan, &status, &wl->bss_list); + if (unlikely(err)) { + status = WL_SCAN_RESULTS_ABORTED; + WL_ERR(("Abort iscan\n")); + } + rtnl_unlock(); + iscan->iscan_handler[status] (wl); + } + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + WL_DBG(("%s was terminated\n", __func__)); + + return 0; +} + +static void wl_iscan_timer(unsigned long data) +{ + struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; + + if (iscan) { + iscan->timer_on = 0; + WL_DBG(("timer expired\n")); + wl_wakeup_iscan(iscan); + } +} + +static s32 wl_invoke_iscan(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); + int err = 0; + + if (wl->iscan_on && !iscan->tsk) { + iscan->state = WL_ISCAN_STATE_IDLE; + sema_init(&iscan->sync, 0); + iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); + if (IS_ERR(iscan->tsk)) { + WL_ERR(("Could not create iscan thread\n")); + iscan->tsk = NULL; + return -ENOMEM; + } + } + + return err; +} + +static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) +{ + memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler)); + iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done; + iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress; + iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending; + iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted; + iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted; +} + +static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted) +{ + + struct net_device *ndev = wl_to_prmry_ndev(wl); + WL_DBG(("Enter \n")); + if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + WL_ERR(("Scan complete while device not scanning\n")); + return; + } + if (wl->p2p_on) + clear_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status); + + if (likely(wl->scan_request)) { + cfg80211_scan_done(wl->scan_request, aborted); + wl_set_mpc(ndev, 1); + wl->scan_request = NULL; + } +} + +static s32 wl_escan_handler(struct wl_priv *wl, + struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 err = BCME_OK; + s32 status = ntoh32(e->status); + wl_bss_info_t *bi; + wl_escan_result_t *escan_result; + wl_bss_info_t *bss = NULL; + wl_scan_results_t *list; + u32 bi_length; + u32 i; + WL_DBG((" enter event type : %d, status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + if (!wl->escan_on && + !test_bit(WL_STATUS_SCANNING, &wl->status)) { + WL_ERR(("escan is not ready \n")); + return err; + } + + if (status == WLC_E_STATUS_PARTIAL) { + WL_INFO(("WLC_E_STATUS_PARTIAL \n")); + escan_result = (wl_escan_result_t *) data; + if (dtoh16(escan_result->bss_count) != 1) { + WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); + goto exit; + } + bi = escan_result->bss_info; + bi_length = dtoh32(bi->length); + if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { + WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); + goto exit; + } + list = (wl_scan_results_t *)wl->escan_info.escan_buf; + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + WL_ERR(("Buffer is too small: ignoring\n")); + goto exit; + } +#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 + for (i = 0; i < list->count; i++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + : list->bss_info; + + if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) && + bi->SSID_len == bss->SSID_len && + !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == + (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + bss->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && + (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + bss->RSSI = bi->RSSI; + bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; + } + + goto exit; + } + } + memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + list->count++; + + } + else if (status == WLC_E_STATUS_SUCCESS) { + wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + if (likely(wl->scan_request)) { + rtnl_lock(); + WL_INFO(("ESCAN COMPLETED\n")); + wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; + wl_inform_bss(wl); + wl_notify_escan_complete(wl, false); + rtnl_unlock(); + } + } +exit: + return err; +} + +static s32 wl_init_iscan(struct wl_priv *wl) +{ + struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); + int err = 0; + + if (wl->iscan_on) { + iscan->dev = wl_to_prmry_ndev(wl); + iscan->state = WL_ISCAN_STATE_IDLE; + wl_init_iscan_handler(iscan); + iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; + init_timer(&iscan->timer); + iscan->timer.data = (unsigned long) iscan; + iscan->timer.function = wl_iscan_timer; + sema_init(&iscan->sync, 0); + iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); + if (IS_ERR(iscan->tsk)) { + WL_ERR(("Could not create iscan thread\n")); + iscan->tsk = NULL; + return -ENOMEM; + } + iscan->data = wl; + } else if (wl->escan_on) { + wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; + wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + } + + return err; +} + +static void wl_init_fw(struct wl_fw_ctrl *fw) +{ + fw->status = 0; +} + +static s32 wl_init_priv(struct wl_priv *wl) +{ + struct wiphy *wiphy = wl_to_wiphy(wl); + s32 err = 0; + s32 i = 0; + + wl->scan_request = NULL; + wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); + wl->iscan_on = true; + wl->escan_on = false; + wl->roam_on = false; + wl->iscan_kickstart = false; + wl->active_scan = true; + wl->dongle_up = false; + wl->rf_blocked = false; + + for (i = 0; i < VWDEV_CNT; i++) + wl->vwdev[i] = NULL; + + init_waitqueue_head(&wl->dongle_event_wait); + wl_init_eq(wl); + err = wl_init_priv_mem(wl); + if (unlikely(err)) + return err; + if (unlikely(wl_create_event_handler(wl))) + return -ENOMEM; + wl_init_event_handler(wl); + mutex_init(&wl->usr_sync); + err = wl_init_iscan(wl); + if (unlikely(err)) + return err; + wl_init_fw(wl->fw); + wl_init_conf(wl->conf); + wl_init_prof(wl->profile); + wl_link_down(wl); + wl_cfgp2p_init_priv(wl); + + return err; +} + +static void wl_deinit_priv(struct wl_priv *wl) +{ + wl_destroy_event_handler(wl); + wl->dongle_up = false; /* dongle down */ + wl_flush_eq(wl); + wl_link_down(wl); + wl_term_iscan(wl); + wl_deinit_priv_mem(wl); +} + +s32 wl_cfg80211_attach(struct net_device *ndev, void *data) +{ + struct wireless_dev *wdev; + struct wl_priv *wl; + struct wl_iface *ci; + s32 err = 0; + + WL_TRACE(("In\n")); + if (unlikely(!ndev)) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL); + if (unlikely(!wl_cfg80211_dev)) { + WL_ERR(("wl_cfg80211_dev is invalid\n")); + return -ENOMEM; + } + WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func())); + wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev); + if (unlikely(IS_ERR(wdev))) + return -ENOMEM; + + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + wl = wdev_to_wl(wdev); + wl->wdev = wdev; + wl->pub = data; + + ci = (struct wl_iface *)wl_to_ci(wl); + ci->wl = wl; + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + + err = wl_init_priv(wl); + if (unlikely(err)) { + WL_ERR(("Failed to init iwm_priv (%d)\n", err)); + goto cfg80211_attach_out; + } + + err = wl_setup_rfkill(wl); + if (unlikely(err)) { + WL_ERR(("Failed to setup rfkill %d\n", err)); + goto cfg80211_attach_out; + } + + wl_set_drvdata(wl_cfg80211_dev, ci); + set_bit(WL_STATUS_READY, &wl->status); + + return err; + +cfg80211_attach_out: + err = wl_setup_rfkill(wl); + wl_free_wdev(wl); + return err; +} + +void wl_cfg80211_detach(void) +{ + struct wl_priv *wl; + + wl = WL_PRIV_GET(); + + WL_TRACE(("In\n")); + + rfkill_unregister(wl->rfkill); + rfkill_destroy(wl->rfkill); + + wl_deinit_priv(wl); + wl_free_wdev(wl); + wl_set_drvdata(wl_cfg80211_dev, NULL); + kfree(wl_cfg80211_dev); + wl_cfg80211_dev = NULL; + wl_clear_sdio_func(); +} + +static void wl_wakeup_event(struct wl_priv *wl) +{ + up(&wl->event_sync); +} + +static s32 wl_event_handler(void *data) +{ + struct net_device *netdev; + struct wl_priv *wl = (struct wl_priv *)data; + struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; + struct wl_event_q *e; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + allow_signal(SIGTERM); + while (likely(!down_interruptible(&wl->event_sync))) { + if (kthread_should_stop()) + break; + e = wl_deq_event(wl); + if (unlikely(!e)) { + WL_ERR(("eqeue empty..\n")); + BUG(); + } + WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); + netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); + if (!netdev) + netdev = wl_to_prmry_ndev(wl); + if (wl->evt_handler[e->etype]) { + wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); + } else { + WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); + } + wl_put_event(e); + } + WL_DBG(("%s was terminated\n", __func__)); + return 0; +} + +void +wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +{ + u32 event_type = ntoh32(e->event_type); + struct wl_priv *wl = WL_PRIV_GET(); + +#if (WL_DBG_LEVEL > 0) + s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? + wl_dbg_estr[event_type] : (s8 *) "Unknown"; + WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); +#endif /* (WL_DBG_LEVEL > 0) */ + + if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) + wl_wakeup_event(wl); +} + +static void wl_init_eq(struct wl_priv *wl) +{ + wl_init_eq_lock(wl); + INIT_LIST_HEAD(&wl->eq_list); +} + +static void wl_flush_eq(struct wl_priv *wl) +{ + struct wl_event_q *e; + + wl_lock_eq(wl); + while (!list_empty(&wl->eq_list)) { + e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); + } + wl_unlock_eq(wl); +} + +/* +* retrieve first queued event from head +*/ + +static struct wl_event_q *wl_deq_event(struct wl_priv *wl) +{ + struct wl_event_q *e = NULL; + + wl_lock_eq(wl); + if (likely(!list_empty(&wl->eq_list))) { + e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); + list_del(&e->eq_list); + } + wl_unlock_eq(wl); + + return e; +} + +/* + * push event to tail of the queue + */ + +static s32 +wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg, + void *data) +{ + struct wl_event_q *e; + s32 err = 0; + uint32 evtq_size; + uint32 data_len; + + data_len = 0; + if (data) + data_len = ntoh32(msg->datalen); + evtq_size = sizeof(struct wl_event_q) + data_len; + e = kzalloc(evtq_size, GFP_KERNEL); + if (unlikely(!e)) { + WL_ERR(("event alloc failed\n")); + return -ENOMEM; + } + e->etype = event; + memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); + if (data) + memcpy(e->edata, data, data_len); + wl_lock_eq(wl); + list_add_tail(&e->eq_list, &wl->eq_list); + wl_unlock_eq(wl); + + return err; +} + +static void wl_put_event(struct wl_event_q *e) +{ + kfree(e); +} + +/* TODO: this has been changed to wl_cfg80211_set_sdio_func in FALCON + * Keep is as-is in P2P Twig + */ +void wl_cfg80211_set_sdio_func(void *func) +{ + cfg80211_sdio_func = (struct sdio_func *)func; +} + +static void wl_clear_sdio_func(void) +{ + cfg80211_sdio_func = NULL; +} + +struct sdio_func *wl_cfg80211_get_sdio_func(void) +{ + return cfg80211_sdio_func; +} + +static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) +{ + s32 infra = 0; + s32 ap = 0; + s32 err = 0; + + switch (iftype) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + WL_ERR(("type (%d) : currently we do not support this mode\n", + iftype)); + err = -EINVAL; + return err; + case NL80211_IFTYPE_ADHOC: + break; + case NL80211_IFTYPE_STATION: + infra = 1; + break; + default: + err = -EINVAL; + WL_ERR(("invalid type (%d)\n", iftype)); + return err; + } + infra = htod32(infra); + ap = htod32(ap); + WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra)); + err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + return err; + } + err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_AP error (%d)\n", err)); + return err; + } + + return -EINPROGRESS; +} +#ifdef NOT_YET +static s32 wl_dongle_save_eventmsg(struct wl_priv *wl) +{ + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + struct net_device *ndev = wl_to_prmry_ndev(wl); + /* Room for "event_msgs" + '\0' + bitvec */ + err = wl_cfgp2p_bssiovar_get(ndev, "event_msgs", 0, + eventmask, WL_EVENTING_MASK_LEN); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + } else { + memcpy(wl->last_eventmask, eventmask, WL_EVENTING_MASK_LEN); + } + return err; +} + +static s32 wl_dongle_disable_eventmsg(struct wl_priv *wl) +{ + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + struct net_device *ndev = wl_to_prmry_ndev(wl); + /* Only Enable IF EVENT */ + setbit(eventmask, WLC_E_IF); + + err = wl_cfgp2p_bssiovar_set(ndev, "event_msgs", 0, + eventmask, WL_EVENTING_MASK_LEN); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + } + + return err; +} + + +static s32 wl_dongle_restore_eventmsg(struct wl_priv *wl) +{ + s32 err = 0; + struct net_device *ndev = wl_to_prmry_ndev(wl); + err = wl_cfgp2p_bssiovar_set(ndev, "event_msgs", 0, + wl->last_eventmask, WL_EVENTING_MASK_LEN); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + } + + return err; +} +#endif /* NOT_YET */ + +static s32 wl_dongle_eventmsg(struct net_device *ndev) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + + /* Setup event_msgs */ + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("Get event_msgs error (%d)\n", err)); + goto dongle_eventmsg_out; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + + setbit(eventmask, WLC_E_SET_SSID); + setbit(eventmask, WLC_E_PRUNE); + setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_REASSOC); + setbit(eventmask, WLC_E_REASSOC_IND); + setbit(eventmask, WLC_E_DEAUTH_IND); + setbit(eventmask, WLC_E_DISASSOC_IND); + setbit(eventmask, WLC_E_DISASSOC); + setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_ASSOC_IND); + setbit(eventmask, WLC_E_PSK_SUP); + setbit(eventmask, WLC_E_LINK); + setbit(eventmask, WLC_E_NDIS_LINK); + setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_PMKID_CACHE); + setbit(eventmask, WLC_E_TXFAIL); + setbit(eventmask, WLC_E_JOIN_START); + setbit(eventmask, WLC_E_SCAN_COMPLETE); + setbit(eventmask, WLC_E_ACTION_FRAME_RX); + setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE); + setbit(eventmask, WLC_E_P2P_PROBREQ_MSG); + setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); + setbit(eventmask, WLC_E_ESCAN_RESULT); + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("Set event_msgs error (%d)\n", err)); + goto dongle_eventmsg_out; + } + +dongle_eventmsg_out: + return err; +} + +#ifndef EMBEDDED_PLATFORM +static s32 wl_dongle_country(struct net_device *ndev, u8 ccode) +{ + + s32 err = 0; + + return err; +} + +static s32 wl_dongle_up(struct net_device *ndev, u32 up) +{ + s32 err = 0; + + err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up)); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + } + return err; +} + +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) +{ + s32 err = 0; + + WL_TRACE(("In\n")); + err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode)); + if (unlikely(err)) { + WL_ERR(("WLC_SET_PM error (%d)\n", err)); + } + return err; +} + +static s32 +wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Match Host and Dongle rx alignment */ + bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, + sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("txglomalign error (%d)\n", err)); + goto dongle_glom_out; + } + /* disable glom option per default */ + bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("txglom error (%d)\n", err)); + goto dongle_glom_out; + } +dongle_glom_out: + return err; +} + +static s32 +wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + if (roamvar) { + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, + sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("bcn_timeout error (%d)\n", err)); + goto dongle_rom_out; + } + } + /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (unlikely(err)) { + WL_ERR(("roam_off error (%d)\n", err)); + goto dongle_rom_out; + } +dongle_rom_out: + return err; +} + +static s32 +wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, + s32 scan_unassoc_time) +{ + s32 err = 0; + + err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, + sizeof(scan_assoc_time)); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("Scan assoc time is not supported\n")); + } else { + WL_ERR(("Scan assoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, + sizeof(scan_unassoc_time)); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("Scan unassoc time is not supported\n")); + } else { + WL_ERR(("Scan unassoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + +dongle_scantime_out: + return err; +} + +static s32 +wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) +{ + /* Room for "event_msgs" + '\0' + bitvec */ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Set ARP offload */ + bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO(("arpoe is not supported\n")); + else + WL_ERR(("arpoe error (%d)\n", err)); + + goto dongle_offload_out; + } + bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO(("arp_ol is not supported\n")); + else + WL_ERR(("arp_ol error (%d)\n", err)); + + goto dongle_offload_out; + } + +dongle_offload_out: + return err; +} + +static s32 wl_pattern_atoh(s8 *src, s8 *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { + WL_ERR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + WL_ERR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + dst[i] = (u8) simple_strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) +{ + /* Room for "event_msgs" + '\0' + bitvec */ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + const s8 *str; + struct wl_pkt_filter pkt_filter; + struct wl_pkt_filter *pkt_filterp; + s32 buf_len; + s32 str_len; + u32 mask_size; + u32 pattern_size; + s8 buf[256]; + s32 err = 0; + + /* add a default packet filter pattern */ + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(100); + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(0); + + /* Parse filter type. */ + pkt_filter.type = htod32(0); + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(0); + + /* Parse pattern filter mask. */ + mask_size = htod32(wl_pattern_atoh("0xff", + (char *)pkt_filterp->u.pattern. + mask_and_pattern)); + + /* Parse pattern filter pattern. */ + pattern_size = htod32(wl_pattern_atoh("0x00", + (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + WL_ERR(("Mask and pattern not the same size\n")); + err = -EINVAL; + goto dongle_filter_out; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local + * variable (keep_alive_pkt), and + * then memcpy'ed into buffer (keep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("filter not supported\n")); + } else { + WL_ERR(("filter (%d)\n", err)); + } + goto dongle_filter_out; + } + + /* set mode to allow pattern */ + bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, + sizeof(iovbuf)); + err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("filter_mode not supported\n")); + } else { + WL_ERR(("filter_mode (%d)\n", err)); + } + goto dongle_filter_out; + } + +dongle_filter_out: + return err; +} +#endif /* !EMBEDDED_PLATFORM */ + +s32 wl_config_dongle(struct wl_priv *wl, bool need_lock) +{ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + struct net_device *ndev; + struct wireless_dev *wdev; + s32 err = 0; + + WL_TRACE(("In\n")); + if (wl->dongle_up) + return err; + + ndev = wl_to_prmry_ndev(wl); + wdev = ndev->ieee80211_ptr; + if (need_lock) + rtnl_lock(); + err = wl_dongle_eventmsg(ndev); + if (unlikely(err)) + goto default_conf_out; +#ifndef EMBEDDED_PLATFORM + err = wl_dongle_up(ndev, 0); + if (unlikely(err)) + goto default_conf_out; + err = wl_dongle_country(ndev, 0); + if (unlikely(err)) + goto default_conf_out; + err = wl_dongle_power(ndev, PM_FAST); + if (unlikely(err)) + goto default_conf_out; + err = wl_dongle_glom(ndev, 0, DHD_SDALIGN); + if (unlikely(err)) + goto default_conf_out; + err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3); + if (unlikely(err)) + goto default_conf_out; + err = wl_dongle_eventmsg(ndev); + if (unlikely(err)) + goto default_conf_out; + + wl_dongle_scantime(ndev, 40, 80); + wl_dongle_offload(ndev, 1, 0xf); + wl_dongle_filter(ndev, 1); +#endif /* !EMBEDDED_PLATFORM */ + + /* TODO: Check if this is ever needed */ + err = wl_dongle_mode(ndev, wdev->iftype); + if (unlikely(err && err != -EINPROGRESS)) + goto default_conf_out; + err = wl_dongle_probecap(wl); + if (unlikely(err)) + goto default_conf_out; + + /* -EINPROGRESS: Call commit handler */ + +default_conf_out: + if (need_lock) + rtnl_unlock(); + + wl->dongle_up = true; + + return err; + +} + +static s32 wl_update_wiphybands(struct wl_priv *wl) +{ + struct wiphy *wiphy; + s32 phy_list; + s8 phy; + s32 err = 0; + + err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list, + sizeof(phy_list)); + if (unlikely(err)) { + WL_ERR(("error (%d)\n", err)); + return err; + } + + phy = ((char *)&phy_list)[1]; + WL_DBG(("%c phy\n", phy)); + if (phy == 'n' || phy == 'a') { + wiphy = wl_to_wiphy(wl); + wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + } + + return err; +} + +static s32 __wl_cfg80211_up(struct wl_priv *wl) +{ + s32 err = 0; + + WL_TRACE(("In\n")); + wl_debugfs_add_netdev_params(wl); + + err = wl_config_dongle(wl, false); + if (unlikely(err)) + return err; + + wl_invoke_iscan(wl); + set_bit(WL_STATUS_READY, &wl->status); + return err; +} + +static s32 __wl_cfg80211_down(struct wl_priv *wl) +{ + s32 err = 0; + + WL_TRACE(("In\n")); + /* Check if cfg80211 interface is already down */ + if (!test_bit(WL_STATUS_READY, &wl->status)) + return err; /* it is even not ready */ + + set_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + wl_term_iscan(wl); + if (wl->scan_request) { + cfg80211_scan_done(wl->scan_request, true); + + /* BUG: this operation cannot help but here because sdio + * is already down through rmmod process. Need to figure + * out how to address this issue + */ + /* wl_set_mpc(wl_to_ndev(wl), 1); */ + + wl->scan_request = NULL; + } + clear_bit(WL_STATUS_READY, &wl->status); + clear_bit(WL_STATUS_SCANNING, &wl->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + clear_bit(WL_STATUS_CONNECTED, &wl->status); + + wl_debugfs_remove_netdev(wl); + + return err; +} + +s32 wl_cfg80211_up(void) +{ + struct wl_priv *wl; + s32 err = 0; + + WL_TRACE(("In\n")); + wl = WL_PRIV_GET(); + mutex_lock(&wl->usr_sync); + err = __wl_cfg80211_up(wl); + mutex_unlock(&wl->usr_sync); + + return err; +} + +s32 wl_cfg80211_down(void) +{ + struct wl_priv *wl; + s32 err = 0; + + WL_TRACE(("In\n")); + wl = WL_PRIV_GET(); + mutex_lock(&wl->usr_sync); + err = __wl_cfg80211_down(wl); + mutex_unlock(&wl->usr_sync); + + return err; +} + +static s32 wl_dongle_probecap(struct wl_priv *wl) +{ + s32 err = 0; + + err = wl_update_wiphybands(wl); + if (unlikely(err)) + return err; + + return err; +} + +static void *wl_read_prof(struct wl_priv *wl, s32 item) +{ + switch (item) { + case WL_PROF_SEC: + return &wl->profile->sec; + case WL_PROF_ACT: + return &wl->profile->active; + case WL_PROF_BSSID: + return &wl->profile->bssid; + case WL_PROF_SSID: + return &wl->profile->ssid; + } + WL_ERR(("invalid item (%d)\n", item)); + return NULL; +} + +static s32 +wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, + s32 item) +{ + s32 err = 0; + struct wlc_ssid *ssid; + + switch (item) { + case WL_PROF_SSID: + ssid = (wlc_ssid_t *) data; + memset(wl->profile->ssid.SSID, 0, + sizeof(wl->profile->ssid.SSID)); + memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len); + wl->profile->ssid.SSID_len = ssid->SSID_len; + break; + case WL_PROF_BSSID: + if (data) + memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN); + else + memset(wl->profile->bssid, 0, ETHER_ADDR_LEN); + break; + case WL_PROF_SEC: + memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec)); + break; + case WL_PROF_ACT: + wl->profile->active = *(bool *)data; + break; + case WL_PROF_BEACONINT: + wl->profile->beacon_interval = *(u16 *)data; + break; + case WL_PROF_DTIMPERIOD: + wl->profile->dtim_period = *(u8 *)data; + break; + default: + WL_ERR(("unsupported item (%d)\n", item)); + err = -EOPNOTSUPP; + break; + } + + return err; +} + +void wl_cfg80211_dbg_level(u32 level) +{ + /* + * prohibit to change debug level + * by insmod parameter. + * eventually debug level will be configured + * in compile time by using CONFIG_XXX + */ + /* wl_dbg_level = level; */ +} + +static bool wl_is_ibssmode(struct wl_priv *wl) +{ + return wl->conf->mode == WL_MODE_IBSS; +} + +static __used bool wl_is_ibssstarter(struct wl_priv *wl) +{ + return wl->ibss_starter; +} + +static void wl_rst_ie(struct wl_priv *wl) +{ + struct wl_ie *ie = wl_to_ie(wl); + + ie->offset = 0; +} + +static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) +{ + struct wl_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { + WL_ERR(("ei crosses buffer boundary\n")); + return -ENOSPC; + } + ie->buf[ie->offset] = t; + ie->buf[ie->offset + 1] = l; + memcpy(&ie->buf[ie->offset + 2], v, l); + ie->offset += l + 2; + + return err; +} + +static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) +{ + struct wl_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { + WL_ERR(("ei_stream crosses buffer boundary\n")); + return -ENOSPC; + } + memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ie->offset += ie_size; + + return err; +} + +static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size) +{ + struct wl_ie *ie = wl_to_ie(wl); + s32 err = 0; + + if (unlikely(ie->offset > dst_size)) { + WL_ERR(("dst_size is not enough\n")); + return -ENOSPC; + } + memcpy(dst, &ie->buf[0], ie->offset); + + return err; +} + +static u32 wl_get_ielen(struct wl_priv *wl) +{ + struct wl_ie *ie = wl_to_ie(wl); + + return ie->offset; +} + +static void wl_link_up(struct wl_priv *wl) +{ + wl->link_up = true; +} + +static void wl_link_down(struct wl_priv *wl) +{ + struct wl_connect_info *conn_info = wl_to_conn(wl); + + wl->link_up = false; + kfree(conn_info->req_ie); + conn_info->req_ie = NULL; + conn_info->req_ie_len = 0; + kfree(conn_info->resp_ie); + conn_info->resp_ie = NULL; + conn_info->resp_ie_len = 0; +} + +static void wl_lock_eq(struct wl_priv *wl) +{ + spin_lock_irq(&wl->eq_lock); +} + +static void wl_unlock_eq(struct wl_priv *wl) +{ + spin_unlock_irq(&wl->eq_lock); +} + +static void wl_init_eq_lock(struct wl_priv *wl) +{ + spin_lock_init(&wl->eq_lock); +} + +static void wl_delay(u32 ms) +{ + if (ms < 1000 / HZ) { + cond_resched(); + mdelay(ms); + } else { + msleep(ms); + } +} + +static void wl_set_drvdata(struct wl_dev *dev, void *data) +{ + dev->driver_data = data; +} + +static void *wl_get_drvdata(struct wl_dev *dev) +{ + return dev->driver_data; +} + +s32 wl_cfg80211_read_fw(s8 *buf, u32 size) +{ + const struct firmware *fw_entry; + struct wl_priv *wl; + + wl = WL_PRIV_GET(); + + fw_entry = wl->fw->fw_entry; + + if (fw_entry->size < wl->fw->ptr + size) + size = fw_entry->size - wl->fw->ptr; + + memcpy(buf, &fw_entry->data[wl->fw->ptr], size); + wl->fw->ptr += size; + return size; +} + +void wl_cfg80211_release_fw(void) +{ + struct wl_priv *wl; + + wl = WL_PRIV_GET(); + release_firmware(wl->fw->fw_entry); + wl->fw->ptr = 0; +} + +void *wl_cfg80211_request_fw(s8 *file_name) +{ + struct wl_priv *wl; + const struct firmware *fw_entry = NULL; + s32 err = 0; + + WL_TRACE(("In\n")); + WL_DBG(("file name : \"%s\"\n", file_name)); + wl = WL_PRIV_GET(); + + if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) { + err = request_firmware(&wl->fw->fw_entry, file_name, + &wl_cfg80211_get_sdio_func()->dev); + if (unlikely(err)) { + WL_ERR(("Could not download fw (%d)\n", err)); + goto req_fw_out; + } + set_bit(WL_FW_LOADING_DONE, &wl->fw->status); + fw_entry = wl->fw->fw_entry; + if (fw_entry) { + WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size, + fw_entry->data)); + } + } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) { + err = request_firmware(&wl->fw->fw_entry, file_name, + &wl_cfg80211_get_sdio_func()->dev); + if (unlikely(err)) { + WL_ERR(("Could not download nvram (%d)\n", err)); + goto req_fw_out; + } + set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status); + fw_entry = wl->fw->fw_entry; + if (fw_entry) { + WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size, + fw_entry->data)); + } + } else { + WL_DBG(("Downloading already done. Nothing to do more\n")); + err = -EPERM; + } + +req_fw_out: + if (unlikely(err)) { + return NULL; + } + wl->fw->ptr = 0; + return (void *)fw_entry->data; +} + +s8 *wl_cfg80211_get_fwname(void) +{ + struct wl_priv *wl; + + wl = WL_PRIV_GET(); + strcpy(wl->fw->fw_name, WL_4329_FW_FILE); + return wl->fw->fw_name; +} + +s8 *wl_cfg80211_get_nvramname(void) +{ + struct wl_priv *wl; + + wl = WL_PRIV_GET(); + strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE); + return wl->fw->nvram_name; +} + +static void wl_set_mpc(struct net_device *ndev, int mpc) +{ +} + +static int wl_debugfs_add_netdev_params(struct wl_priv *wl) +{ + char buf[10+IFNAMSIZ]; + struct dentry *fd; + s32 err = 0; + + WL_TRACE(("In\n")); + sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name); + wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir); + + fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir, + (u16 *)&wl->profile->beacon_interval); + if (!fd) { + err = -ENOMEM; + goto err_out; + } + + fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir, + (u8 *)&wl->profile->dtim_period); + if (!fd) { + err = -ENOMEM; + goto err_out; + } + +err_out: + return err; +} + +static void wl_debugfs_remove_netdev(struct wl_priv *wl) +{ + WL_DBG(("Enter \n")); +} + +static __used void wl_dongle_poweron(struct wl_priv *wl) +{ + + WL_DBG(("Enter \n")); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); + +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 0); +#endif +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 1); +#endif + wl_cfg80211_resume(wl_to_wiphy(wl)); +} + +static __used void wl_dongle_poweroff(struct wl_priv *wl) +{ + + + WL_DBG(("Enter \n")); + wl_cfg80211_suspend(wl_to_wiphy(wl)); + +#if defined(BCMLXSDMMC) + sdioh_stop(NULL); +#endif + /* clean up dtim_skip setting */ + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); +} + +static const struct rfkill_ops wl_rfkill_ops = { + .set_block = wl_rfkill_set, +}; + +static int wl_rfkill_set(void *data, bool blocked) +{ + struct wl_priv *wl = (struct wl_priv *)data; + + WL_DBG(("Enter \n")); + WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); + + wl->rf_blocked = blocked; + + return 0; +} + +static int wl_setup_rfkill(struct wl_priv *wl) +{ + s32 err; + + WL_DBG(("Enter \n")); + wl->rfkill = rfkill_alloc("brcmfmac-wifi", + &wl_cfg80211_get_sdio_func()->dev, + RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); + + if (!wl->rfkill) { + err = -ENOMEM; + goto err_out; + } + + err = rfkill_register(wl->rfkill); + + if (err) + rfkill_destroy(wl->rfkill); + +err_out: + return err; +} diff --git a/src/wl/sys/wl_cfg80211.h b/src/wl/sys/wl_cfg80211.h new file mode 100644 index 0000000..bb2f0e4 --- /dev/null +++ b/src/wl/sys/wl_cfg80211.h @@ -0,0 +1,521 @@ +/* + * Linux cfg80211 driver + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: wl_cfg80211.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $ + */ + +#ifndef _wl_cfg80211_h_ +#define _wl_cfg80211_h_ + +#include <linux/wireless.h> +#include <typedefs.h> +#include <proto/ethernet.h> +#include <wlioctl.h> +#include <linux/wireless.h> +#include <net/cfg80211.h> +#include <linux/rfkill.h> + +struct wl_conf; +struct wl_iface; +struct wl_priv; +struct wl_security; +struct wl_ibss; + +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define htodchanspec(i) i +#define dtohchanspec(i) i + +#define WL_DBG_NONE 0 +#define WL_DBG_DBG (1 << 2) +#define WL_DBG_INFO (1 << 1) +#define WL_DBG_ERR (1 << 0) +#define WL_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1) + +/* 0 invalidates all debug messages. default is 1 */ +#define WL_DBG_LEVEL 0xFF + +#define WL_ERR(args) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + printk(KERN_ERR "CFG80211-ERROR) %s : ", __func__); \ + printk args; \ + } \ +} while (0) +#define WL_INFO(args) \ +do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + printk(KERN_ERR "CFG80211-INFO) %s : ", __func__); \ + printk args; \ + } \ +} while (0) +#if (WL_DBG_LEVEL > 0) +#define WL_DBG(args) \ +do { \ + if (wl_dbg_level & WL_DBG_DBG) { \ + printk(KERN_ERR "CFG80211-DEBUG) %s :", __func__); \ + printk args; \ + } \ +} while (0) +#else /* !(WL_DBG_LEVEL > 0) */ +#define WL_DBG(args) +#endif /* (WL_DBG_LEVEL > 0) */ + +#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */ +#define WL_NUM_SCAN_MAX 1 +#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used + * for 2.6.33 kernel + * or later + */ +#define WL_SCAN_BUF_MAX (1024 * 8) +#define WL_TLV_INFO_MAX 1024 +#define WL_SCAN_IE_LEN_MAX 2048 +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 /* + * needs to grab assoc info from dongle to + * report it to cfg80211 through "connect" + * event + */ +#define WL_IOCTL_LEN_MAX 1024 +#define WL_EXTRA_BUF_MAX 2048 +#define WL_ISCAN_BUF_MAX 2048 /* + * the buf lengh can be WLC_IOCTL_MAXLEN (8K) + * to reduce iteration + */ +#define WL_ISCAN_TIMER_INTERVAL_MS 3000 +#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) +#define WL_AP_MAX 256 /* virtually unlimitted as long + * as kernel memory allows + */ +#define WL_FILE_NAME_MAX 256 + +/* WiFi Direct */ +#define WL_P2P_WILDCARD_SSID "DIRECT-" +#define WL_P2P_WILDCARD_SSID_LEN 7 +#define WL_P2P_INTERFACE_PREFIX "p2p" +#define WL_P2P_TEMP_CHAN "11" + +/* dongle status */ +enum wl_status { + WL_STATUS_READY = 0, + WL_STATUS_SCANNING, + WL_STATUS_SCAN_ABORTING, + WL_STATUS_CONNECTING, + WL_STATUS_CONNECTED +}; + +/* wi-fi mode */ +enum wl_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +/* dongle profile list */ +enum wl_prof_list { + WL_PROF_MODE, + WL_PROF_SSID, + WL_PROF_SEC, + WL_PROF_IBSS, + WL_PROF_BAND, + WL_PROF_BSSID, + WL_PROF_ACT, + WL_PROF_BEACONINT, + WL_PROF_DTIMPERIOD +}; + +/* dongle iscan state */ +enum wl_iscan_state { + WL_ISCAN_STATE_IDLE, + WL_ISCAN_STATE_SCANING +}; + +/* donlge escan state */ +enum wl_escan_state { + WL_ESCAN_STATE_IDLE, + WL_ESCAN_STATE_SCANING +}; +/* fw downloading status */ +enum wl_fw_status { + WL_FW_LOADING_DONE, + WL_NVRAM_LOADING_DONE +}; + +/* dongle status */ +enum wl_cfgp2p_status { + WLP2P_STATUS_DISCOVERY_ON, + WLP2P_STATUS_SEARCH_ENABLED, + WLP2P_STATUS_IF_ADD, + WLP2P_STATUS_IF_DEL, + WLP2P_STATUS_IF_CHANGING, + WLP2P_STATUS_IF_CHANGED, + WLP2P_STATUS_LISTEN_EXPIRED, + WLP2P_STATUS_ACTION_TX_COMPLETED, + WLP2P_STATUS_GROUP_OWNER, + WLP2P_STATUS_GROUP_CLIENT, + WLP2P_STATUS_SCANNING, + WLP2P_STATUS_SCAN_ABORTING, + WLP2P_STATUS_CONNECTING, + WLP2P_STATUS_CONNECTED +}; +/* beacon / probe_response */ +struct beacon_proberesp { + __le64 timestamp; + __le16 beacon_int; + __le16 capab_info; + u8 variable[0]; +} __attribute__ ((packed)); + +/* dongle configuration */ +struct wl_conf { + u32 mode; /* adhoc , infrastructure or ap */ + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, + struct net_device *ndev, const wl_event_msg_t *e, void *data); + +/* representing interface of cfg80211 plane */ +struct wl_iface { + struct wl_priv *wl; +}; + +struct wl_dev { + void *driver_data; /* to store cfg80211 object information */ +}; + +/* bss inform structure for cfg80211 interface */ +struct wl_cfg80211_bss_info { + u16 band; + u16 channel; + s16 rssi; + u16 frame_len; + u8 frame_buf[1]; +}; + +/* basic structure of scan request */ +struct wl_scan_req { + struct wlc_ssid ssid; +}; + +/* basic structure of information element */ +struct wl_ie { + u16 offset; + u8 buf[WL_TLV_INFO_MAX]; +}; + +/* event queue for cfg80211 main event */ +struct wl_event_q { + struct list_head eq_list; + u32 etype; + wl_event_msg_t emsg; + s8 edata[1]; +}; + +/* security information with currently associated ap */ +struct wl_security { + u32 wpa_versions; + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; + u32 wpa_auth; +}; + +/* ibss information for currently joined ibss network */ +struct wl_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; +}; + +/* dongle profile */ +struct wl_profile { + u32 mode; + struct wlc_ssid ssid; + u8 bssid[ETHER_ADDR_LEN]; + u16 beacon_interval; + u8 dtim_period; + struct wl_security sec; + struct wl_ibss ibss; + s32 band; + bool active; +}; + +typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); + +/* dongle iscan controller */ +struct wl_iscan_ctrl { + struct net_device *dev; + struct timer_list timer; + u32 timer_ms; + u32 timer_on; + s32 state; + struct task_struct *tsk; + struct semaphore sync; + ISCAN_HANDLER iscan_handler[WL_SCAN_ERSULTS_LAST]; + void *data; + s8 ioctl_buf[WLC_IOCTL_SMLEN]; + s8 scan_buf[WL_ISCAN_BUF_MAX]; +}; + +/* association inform */ +struct wl_connect_info { + u8 *req_ie; + s32 req_ie_len; + u8 *resp_ie; + s32 resp_ie_len; +}; + +/* firmware /nvram downloading controller */ +struct wl_fw_ctrl { + const struct firmware *fw_entry; + unsigned long status; + u32 ptr; + s8 fw_name[WL_FILE_NAME_MAX]; + s8 nvram_name[WL_FILE_NAME_MAX]; +}; + +/* assoc ie length */ +struct wl_assoc_ielen { + u32 req_len; + u32 resp_len; +}; + +/* wpa2 pmk list */ +struct wl_pmk_list { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID - 1]; +}; +/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not + * confuse this with a bsscfg index. This value is an index into the + * saved_ie[] array of structures which in turn contains a bsscfg index field. + */ +typedef enum { + P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ + P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ + P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ + P2PAPI_BSSCFG_MAX +} p2p_bsscfg_type_t; + +#define IE_MAX_LEN 300 +/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ +typedef struct p2p_saved_ie_s { + u8 p2p_probe_req_ie[IE_MAX_LEN]; + u32 p2p_probe_req_ie_len; + u8 p2p_probe_res_ie[IE_MAX_LEN]; + u32 p2p_probe_res_ie_len; + u8 p2p_assoc_req_ie[IE_MAX_LEN]; + u32 p2p_assoc_req_ie_len; + u8 p2p_assoc_res_ie[IE_MAX_LEN]; + u32 p2p_assoc_res_ie_len; + u8 p2p_beacon_ie[IE_MAX_LEN]; + u32 p2p_beacon_ie_len; +} p2p_saved_ie_t; + +struct p2p_bss { + u32 bssidx; + struct net_device *dev; + p2p_saved_ie_t saved_ie; +}; + +#define ESCAN_BUF_SIZE (64 * 1024) + +struct escan_info { + u32 escan_state; + u8 escan_buf[ESCAN_BUF_SIZE]; + struct wiphy *wiphy; +}; +#define VWDEV_CNT 3 +/* dongle private data of cfg80211 interface */ +struct wl_priv { + struct wireless_dev *wdev; /* representing wl cfg80211 device */ + struct wireless_dev *vwdev[VWDEV_CNT]; + struct wl_conf *conf; /* dongle configuration */ + struct cfg80211_scan_request *scan_request; /* scan request object */ + EVENT_HANDLER evt_handler[WLC_E_LAST]; + struct list_head eq_list; /* used for event queue */ + spinlock_t eq_lock; /* for event queue synchronization */ + struct mutex usr_sync; /* maily for dongle up/down synchronization */ + struct wl_scan_results *bss_list; + struct wl_scan_results *scan_results; + + /* scan request object for internal purpose */ + struct wl_scan_req *scan_req_int; + + /* bss information for cfg80211 layer */ + struct wl_cfg80211_bss_info *bss_info; + /* information element object for internal purpose */ + struct wl_ie ie; + u8 scan_ie_buf[2048]; + int scan_ie_len; + struct ether_addr bssid; /* bssid of currently engaged network */ + + /* for synchronization of main event thread */ + struct semaphore event_sync; + struct wl_profile *profile; /* holding dongle profile */ + struct wl_iscan_ctrl *iscan; /* iscan controller */ + + /* association information container */ + struct wl_connect_info conn_info; + + /* control firwmare and nvram paramter downloading */ + struct wl_fw_ctrl *fw; + struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ + struct task_struct *event_tsk; /* task of main event handler thread */ + unsigned long status; /* current dongle status */ + void *pub; + u32 channel; /* current channel */ + bool iscan_on; /* iscan on/off switch */ + bool iscan_kickstart; /* indicate iscan already started */ + bool escan_on; /* escan on/off switch */ + struct escan_info escan_info; /* escan information */ + bool active_scan; /* current scan mode */ + bool ibss_starter; /* indicates this sta is ibss starter */ + bool link_up; /* link/connection up flag */ + + /* indicate whether dongle to support power save mode */ + bool pwr_save; + bool dongle_up; /* indicate whether dongle up or not */ + bool roam_on; /* on/off switch for dongle self-roaming */ + bool scan_tried; /* indicates if first scan attempted */ + u8 *ioctl_buf; /* ioctl buffer */ + u8 *escan_ioctl_buf; + u8 *extra_buf; /* maily to grab assoc information */ + struct dentry *debugfsdir; + struct rfkill *rfkill; + bool rf_blocked; + + struct ieee80211_channel remain_on_chan; + enum nl80211_channel_type remain_on_chan_type; + u64 cache_cookie; + wait_queue_head_t dongle_event_wait; + struct timer_list *listen_timer; + s8 last_eventmask[WL_EVENTING_MASK_LEN]; + bool p2p_on; /* p2p on/off switch */ + bool p2p_scan; + bool p2p_vif_created; + s8 p2p_vir_ifname[IFNAMSIZ]; + unsigned long p2p_status; + struct ether_addr p2p_dev_addr; + struct ether_addr p2p_int_addr; + struct p2p_bss p2p_bss_idx[P2PAPI_BSSCFG_MAX]; + wlc_ssid_t p2p_ssid; + s32 sta_generation; + u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); +}; + +#define wl_to_dev(w) (wiphy_dev(wl->wdev->wiphy)) +#define wl_to_wiphy(w) (w->wdev->wiphy) +#define wiphy_to_wl(w) ((struct wl_priv *)(wiphy_priv(w))) +#define wl_to_wdev(w) (w->wdev) +#define wdev_to_wl(w) ((struct wl_priv *)(wdev_priv(w))) +#define wl_to_prmry_ndev(w) (w->wdev->netdev) +#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define ci_to_wl(c) (ci->wl) +#define wl_to_ci(w) (&w->ci) +#define wl_to_sr(w) (w->scan_req_int) +#define wl_to_ie(w) (&w->ie) +#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) +#define wl_to_iscan(w) (w->iscan) +#define wl_to_conn(w) (&w->conn_info) +#define wiphy_from_scan(w) (w->escan_info.wiphy) +#define wl_to_p2p_bss_ndev(w, type) (wl->p2p_bss_idx[type].dev) +#define wl_to_p2p_bss_bssidx(w, type) (wl->p2p_bss_idx[type].bssidx) +#define wl_to_p2p_bss_saved_ie(w, type) (wl->p2p_bss_idx[type].saved_ie) +#define wl_to_p2p_bss(w, type) (wl->p2p_bss_idx[type]) +static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) +{ + return bss = bss ? + (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; +} +static inline int alloc_idx_vwdev(struct wl_priv *wl) +{ + int i = 0; + for (i = 0; i < VWDEV_CNT; i++) { + if (wl->vwdev[i] == NULL) + return i; + } + return -1; +} + +static inline int get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + int i = 0; + for (i = 0; i < VWDEV_CNT; i++) { + if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev)) + return i; + } + return -1; +} + +#define free_vwdev_by_index(wl, __i) do { \ + if (wl->vwdev[__i] != NULL) \ + kfree(wl->vwdev[__i]); \ + wl->vwdev[__i] = NULL; \ + } while (0) + +#define for_each_bss(list, bss, __i) \ + for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) + +/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. + * In addtion to that, wpa_version is WPA_VERSION_1 + */ +#define is_wps_conn(_sme) \ + ((_sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) && \ + (!_sme->crypto.n_ciphers_pairwise) && \ + (!_sme->crypto.cipher_group)) +extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); +extern void wl_cfg80211_detach(void); +/* event handler from dongle */ +extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); +extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */ +extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */ +extern s32 wl_cfg80211_up(void); /* dongle up */ +extern s32 wl_cfg80211_down(void); /* dongle down */ +extern s32 wl_cfg80211_notify_ifadd(struct net_device *net); +extern s32 wl_cfg80211_notify_ifdel(struct net_device *net); +extern s32 wl_cfg80211_is_progress_ifchange(void); +extern s32 wl_cfg80211_notify_ifchange(void); +extern void wl_cfg80211_dbg_level(u32 level); +extern void *wl_cfg80211_request_fw(s8 *file_name); +extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size); +extern void wl_cfg80211_release_fw(void); +extern s8 *wl_cfg80211_get_fwname(void); +extern s8 *wl_cfg80211_get_nvramname(void); + +/* do scan abort */ +extern s32 +wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev); + +extern s32 +wl_cfg80211_if_is_group_owner(void); +#endif /* _wl_cfg80211_h_ */ diff --git a/src/wl/sys/wl_cfgp2p.c b/src/wl/sys/wl_cfgp2p.c new file mode 100644 index 0000000..a87631c --- /dev/null +++ b/src/wl/sys/wl_cfgp2p.c @@ -0,0 +1,1583 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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$ + */ + + +#include <typedefs.h> +#include <linuxver.h> +#include <osl.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/if_arp.h> +#include <asm/uaccess.h> + +#include <bcmutils.h> +#include <bcmendian.h> +#include <proto/ethernet.h> +#include <dngl_stats.h> +#include <dhd.h> +#include <dhdioctl.h> +#include <wlioctl.h> + +#include <wl_cfg80211.h> +#include <wl_cfgp2p.h> + + +/* dword align allocation */ +#define WLC_IOCTL_MAXLEN 8192 +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +#define CFGP2P_DBG_NONE 0 +#define CFGP2P_DBG_DBG (1 << 2) +#define CFGP2P_DBG_INFO (1 << 1) +#define CFGP2P_DBG_ERR (1 << 0) +#define CFGP2P_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1) + + +#define CFGP2P_DBG_LEVEL 0xFF /* 0 invalidates all debug messages */ + +u32 cfgp2p_dbg_level = CFGP2P_DBG_ERR | CFGP2P_DBG_INFO | CFGP2P_DBG_DBG; + +#define CFGP2P_ERR(args) \ + do { \ + if (cfgp2p_dbg_level & CFGP2P_DBG_ERR) { \ + printk(KERN_ERR "CFGP2P-ERROR) %s : ", __func__); \ + printk args; \ + } \ + } while (0) +#define CFGP2P_INFO(args) \ + do { \ + if (cfgp2p_dbg_level & CFGP2P_DBG_INFO) { \ + printk(KERN_ERR "CFGP2P-INFO) %s : ", __func__); \ + printk args; \ + } \ + } while (0) +#if (CFGP2P_DBG_LEVEL > 0) +#define CFGP2P_DBG(args) \ + do { \ + if (cfgp2p_dbg_level & CFGP2P_DBG_DBG) { \ + printk(KERN_ERR "CFGP2P-DEBUG) %s :", __func__); \ + printk args; \ + } \ + } while (0) +#else /* !(WL_DBG_LEVEL > 0) */ +#define CFGP2P_DBG(args) +#endif /* (WL_DBG_LEVEL > 0) */ + + +static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; +static s8 scanparambuf[WLC_IOCTL_SMLEN]; +static s8 *smbuf = ioctlbuf; + + +static s32 +wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete); +static s32 +wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) +{ + struct ifreq ifr; + struct wl_ioctl ioc; + mm_segment_t fs; + s32 err = 0; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t)&ioc; + fs = get_fs(); + set_fs(get_ds()); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#else + err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + set_fs(fs); + + return err; +} + +/* + * Format an iovar buffer. + * iovar name is converted to lower case + */ +static s32 +wl_cfgp2p_iovar_mkbuf(const s8 *name, s8 *data, u32 datalen, + s8 *iovar_buf, u32 buflen, u32 *perr) +{ + u32 iovar_len; + iovar_len = (u32) strlen(name) + 1; + + if ((iovar_len + datalen) > buflen) { + + CFGP2P_ERR(("buf too short, %u < %u\n", buflen, (iovar_len + datalen))); + *perr = BCME_BUFTOOSHORT; + return 0; + } + + /* copy data to the buffer past the end of the iovar name string */ + if (datalen > 0) { + memmove(&iovar_buf[iovar_len], data, datalen); + } + + /* copy the name to the beginning of the buffer */ + strcpy(iovar_buf, name); + + + *perr = 0; + return (iovar_len + datalen); +} + +/* + * Format a bsscfg indexed iovar buffer. + * This is a common implementation called by most OSL implementations of + * p2posl_bssiovar_mkbuf(). DO NOT call this function directly from the + * common code -- call p2posl_bssiovar_mkbuf() instead to allow the OSL to + * override the common implementation if necessary. + */ +static s32 +wl_cfgp2p_bssiovar_mkbuf(const s8 *iovar, s32 bssidx, + void *param, s32 paramlen, void *bufptr, s32 buflen, s32 *perr) +{ + const s8 *prefix = "bsscfg:"; + s8 *p; + u32 prefixlen; + u32 namelen; + u32 iolen; + + if (bssidx == 0) { + return wl_cfgp2p_iovar_mkbuf(iovar, (s8 *)param, paramlen, + (s8 *) bufptr, buflen, perr); + } + + prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ + namelen = (u32) strlen(iovar) + 1; /* lengh of iovar name + null */ + iolen = prefixlen + namelen + sizeof(u32) + paramlen; + + if (buflen < 0 || iolen > (u32)buflen) { + CFGP2P_ERR(("buf too short, %u < %u\n", buflen, iolen)); + *perr = BCME_BUFTOOSHORT; + return 0; + } + p = (s8 *)bufptr; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, iovar, namelen); + p += namelen; + + /* bss config index as first param */ + bssidx = htod32(bssidx); + memcpy(p, &bssidx, sizeof(u32)); + p += sizeof(u32); + + /* parameter buffer follows */ + if (paramlen) + memcpy(p, param, paramlen); + + *perr = 0; + + return iolen; + +} + +/* + * Set a bss-indexed iovar on the primary ioctl interface, providing both + * parameter and i/o buffers. + */ + +static s32 +wl_cfgp2p_bssiovar_setbuf(struct net_device *dev, const s8 *iovar, s32 bssidx, + void *param, s32 paramlen, void *bufptr, s32 buflen) +{ + s32 iolen; + s32 err; + iolen = wl_cfgp2p_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, + buflen, &err); + + if (err) + return err; + + return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen, TRUE); +} +/* + * Get a named & bss indexed driver iovar using the primary ioctl interface. + */ +static s32 +wl_cfgp2p_bssiovar_getbuf(struct net_device *dev, const s8 *iovar, int bssidx, + void *param, s32 paramlen, void *bufptr, s32 buflen) +{ + s32 err; + s32 iolen; + iolen = wl_cfgp2p_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err); + + if (unlikely(err)) + return err; + + return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, iolen, FALSE); +} + + +/* + * Get named & bss indexed driver variable to buffer value + * using the primary ioctl interface. + */ +s32 +wl_cfgp2p_bssiovar_get(struct net_device *dev, const s8 *iovar, s32 bssidx, + void *outbuf, s32 len) +{ + s32 err; + + if (len > (s32)sizeof(ioctlbuf)) { + err = wl_cfgp2p_bssiovar_getbuf(dev, iovar, bssidx, NULL, 0, + outbuf, len); + } else { + memset(smbuf, 0, sizeof(ioctlbuf)); + + err = wl_cfgp2p_bssiovar_getbuf(dev, iovar, bssidx, NULL, 0, + smbuf, sizeof(ioctlbuf)); + + if (err == 0) + memcpy(outbuf, smbuf, len); + } + return err; +} +/* + * Set named & bss indexed driver variable to buffer value + * on the primary ioctl interface. + */ +s32 +wl_cfgp2p_bssiovar_set(struct net_device *dev, const s8 *iovar, s32 bssidx, + void *param, s32 paramlen) +{ + + memset(smbuf, 0, sizeof(ioctlbuf)); + + return wl_cfgp2p_bssiovar_setbuf(dev, iovar, bssidx, param, paramlen, smbuf, + sizeof(ioctlbuf)); +} + + +/* + * Set named & bsscfg indexed driver variable to int value + * on the primary ioctl interface. + */ + +s32 +wl_cfgp2p_bssiovar_setint(struct net_device *dev, const s8 *iovar, s32 bssidx, + s32 val) +{ + + val = htod32(val); + + return wl_cfgp2p_bssiovar_set(dev, iovar, bssidx, &val, sizeof(int)); +} + + +s32 +wl_cfgp2p_set_int_bss(struct net_device *dev, s32 ioctl_cmd, s32 val, s32 bssidx) +{ + s32 setval = htod32(val); + return wl_dev_ioctl(dev, WLC_SET_VAR, &setval, sizeof(setval), TRUE); +} + + +s32 +wl_cfgp2p_get_int_bss(struct net_device *dev, s32 ioctl_cmd, s32 *val, s32 bssidx) +{ + s32 ret; + ret = wl_dev_ioctl(dev, WLC_GET_VAR, val, sizeof(*val), FALSE); + if (ret >= 0) { + val = dtoh32(val); + } + return ret; +} + +s32 +wl_cfgp2p_iovar_getbuf_bss(struct net_device *dev, const s8 *iovar, void *param, + s32 paramlen, void *bufptr, s32 buflen, s32 bssidx) +{ + s32 err; + + wl_cfgp2p_iovar_mkbuf(iovar, (s8 *)param, paramlen, (s8 *) bufptr, buflen, + &err); + + if (unlikely(err)) { + CFGP2P_ERR((" mkbuf err %d\n", err)); + } + + return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen, FALSE); +} +/* + * Set a named iovar on a specified BSS, providing both parameter and i/o + * buffers. The iovar name is converted to lower case. + */ +s32 +wl_cfgp2p_iovar_setbuf_bss(struct net_device *dev, const s8 *iovar, + void *param, s32 paramlen, void *bufptr, s32 buflen) +{ + s32 err = BCME_OK; + s32 iolen; + CFGP2P_DBG((" enter\n")); + + iolen = wl_cfgp2p_iovar_mkbuf(iovar, (char *) param, paramlen, (s8 *)bufptr, + buflen, &err); + + if (unlikely(err)) { + CFGP2P_ERR(("iovar = %s\n", iovar)); + return err; + } + err = wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen, TRUE); + CFGP2P_DBG((" leave\n")); + return err; +} + +/* + * Set a named iovar given the parameter buffer, on a specified BSS. + * The iovar name is converted to lower case. + */ +s32 +wl_cfgp2p_iovar_set_bss(struct net_device *dev, const s8 *iovar, void *param, + s32 paramlen) +{ + + s32 ret; + memset(smbuf, 0, sizeof(ioctlbuf)); + CFGP2P_DBG((" enter\n")); + ret = wl_cfgp2p_iovar_setbuf_bss(dev, iovar, param, paramlen, smbuf, + sizeof(ioctlbuf)); + + if (unlikely(ret != 0)) { + CFGP2P_ERR(("set iovar %s failed (%d)\n", + iovar, ret)); + } + CFGP2P_DBG((" leave\n")); + return ret; +} +/* + * Get a parameterless iovar into a given buffer. + * iovar name is converted to lower case + */ +s32 +wl_cfgp2p_iovar_get_bss(struct net_device *dev, const s8 *iovar, void *outbuf, s32 len, + s32 bssidx) +{ + s32 err; + + /* use the return buffer if it is bigger than what we have on the stack */ + if (len > (s32)sizeof(ioctlbuf)) { + err = wl_cfgp2p_iovar_getbuf_bss(dev, iovar, NULL, 0, outbuf, len, bssidx); + } else { + memset(smbuf, 0, sizeof(ioctlbuf)); + err = wl_cfgp2p_iovar_getbuf_bss(dev, iovar, NULL, 0, smbuf, sizeof(ioctlbuf), + bssidx); + if (err == 0) + memcpy(outbuf, smbuf, len); + } + + return err; +} + +/* + * Set named iovar given an integer parameter, on the specified BSS. + * iovar name is converted to lower case + */ +s32 +wl_cfgp2p_iovar_setint_bss(struct net_device *dev, const s8 *iovar, s32 val) +{ + CFGP2P_DBG((" enter\n")); + val = htod32(val); + return wl_cfgp2p_iovar_set_bss(dev, iovar, &val, sizeof(int)); +} + +/* + * Get the named integer iovar on the specified BSS. + * iovar name is converted to lower case + */ +s32 +wl_cfgp2p_iovar_getint_bss(struct net_device *dev, const s8*iovar, s32 *pval, s32 bssidx) +{ + s32 ret; + + ret = wl_cfgp2p_iovar_get_bss(dev, iovar, pval, sizeof(s32), bssidx); + if (ret >= 0) + { + *pval = dtoh32(*pval); + } + return ret; +} + +/* + * Initialize variables related to P2P + * + */ +void +wl_cfgp2p_init_priv(struct wl_priv *wl) +{ + wl->p2p_on = 0; + wl->p2p_scan = 0; /* by default , legacy scan */ + wl->p2p_status = 0; + wl->listen_timer = NULL; + +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + + INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); + INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); + INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); + INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); + INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); + INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); +#undef INIT_IE + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl); + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0; + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; + +} + +/* + * Set P2P functions into firmware + */ +s32 +wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) +{ + s32 ret = BCME_OK; + + /* TODO : Do we have to check whether APSTA is enabled or not ? */ + return ret; +} + +/* Create a new P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT + * @chspec : chspec to use if creating a GO BSS. + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", + ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], + ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); + + err = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifadd", &ifreq, sizeof(ifreq)); + return err; +} + +/* Delete a P2P BSS. + * Parameters: + * @mac : MAC address of the BSS to create + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) +{ + s32 ret; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + CFGP2P_INFO(("---wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5])); + + ret = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifdel", mac, sizeof(*mac)); + + if (unlikely(ret < 0)) { + printk("'wl p2p_ifdel' error %d\n", ret); + } + return ret; +} + +/* Change a P2P Role. + * Parameters: + * @mac : MAC address of the BSS to change a role + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, + chanspec_t chspec) +{ + wl_p2p_if_t ifreq; + s32 err; + struct net_device *netdev = wl_to_prmry_ndev(wl); + + ifreq.type = if_type; + ifreq.chspec = chspec; + memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); + + CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", + ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], + ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], + (if_type == WL_P2P_IF_GO) ? "go" : "client", + (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); + + err = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq)); + + if (unlikely(err < 0)) { + printk("'wl p2p_ifupd' error %d\n", err); + } + return err; +} + + +/* Get the index of a created P2P BSS. + * Parameters: + * @mac : MAC address of the created BSS + * @index : output: index of created BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) +{ + s32 ret; + u8 getbuf[64]; + struct net_device *dev = wl_to_prmry_ndev(wl); + + CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n", + mac->octet[0], mac->octet[1], mac->octet[2], + mac->octet[3], mac->octet[4], mac->octet[5])); + + ret = wl_cfgp2p_iovar_getbuf_bss(dev, "p2p_if", mac, sizeof(*mac), + getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)); + + if (ret == 0) { + memcpy(index, getbuf, sizeof(index)); + CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index)); + } + + return ret; +} + +s32 +wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) +{ + s32 ret = BCME_OK; + struct net_device *ndev = wl_to_prmry_ndev(wl); + CFGP2P_DBG(("enter\n")); + + ret = wl_cfgp2p_iovar_setint_bss(ndev, "p2p_disc", on); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); + } + + return ret; +} + +/* Set the WL driver's P2P mode. + * Parameters : + * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. + * @channel : the channel to listen + * @listen_ms : the time (milli seconds) to wait + * @bssidx : bss index for BSSCFG + * Returns 0 if success + */ + +s32 +wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx) +{ + wl_p2p_disc_st_t discovery_mode; + s32 ret; + struct net_device *dev; + CFGP2P_DBG(("enter\n")); + + if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) { + CFGP2P_ERR((" %d index out of range\n", bssidx)); + return -1; + } + + dev = wl_to_p2p_bss_ndev(wl, bssidx); + if (unlikely(dev == NULL)) { + CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); + return BCME_NOTFOUND; + } + + /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ + discovery_mode.state = mode; + discovery_mode.chspec = CH20MHZ_CHSPEC(channel); + discovery_mode.dwell = listen_ms; + ret = wl_cfgp2p_bssiovar_set(dev, "p2p_state", bssidx, &discovery_mode, + sizeof(discovery_mode)); + + return ret; +} + +/* Get the index of the P2P Discovery BSS */ +s32 +wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) +{ + s32 ret; + struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); + + ret = wl_cfgp2p_iovar_getint_bss(dev, "p2p_dev", index, 0); + CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); + return ret; + } + return ret; +} + +s32 +wl_cfgp2p_init_discovery(struct wl_priv *wl) +{ + + s32 index = 0; + s32 ret = BCME_OK; + + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) { + CFGP2P_ERR(("do nothing, already initialized\n")); + return ret; + } + + ret = wl_cfgp2p_set_discovery(wl, 1); + if (ret < 0) { + CFGP2P_ERR(("set discover error\n")); + return ret; + } + /* Enable P2P Discovery in the WL Driver */ + ret = wl_cfgp2p_get_disc_idx(wl, &index); + + if (ret < 0) { + return ret; + } + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index; + + /* Set the initial discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret != 0)) { + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + wl_cfgp2p_set_discovery(wl, 0); + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; + return 0; + } + return ret; +} + +/* Deinitialize P2P Discovery + * Parameters : + * @wl : wl_private data + * Returns 0 if succes + */ +s32 +wl_cfgp2p_deinit_discovery(struct wl_priv *wl) +{ + s32 ret = BCME_OK; + CFGP2P_DBG(("enter\n")); + + if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { + CFGP2P_ERR(("do nothing, not initialized\n")); + return -1; + } + /* Set the discovery state to SCAN */ + ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ + ret = wl_cfgp2p_set_discovery(wl, 0); + + /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver + * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery + * BSS. + */ + + /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we + * have no discovery BSS. + */ + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; + + return ret; + +} +/* Enable P2P Discovery + * Parameters: + * @wl : wl_private data + * @ie : probe request ie (WPS IE + P2P IE) + * @ie_len : probe request ie length + * Returns 0 if success. + */ +s32 +wl_cfgp2p_enable_discovery(struct wl_priv *wl, const u8 *ie, u32 ie_len) +{ + s32 ret = BCME_OK; + if (test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status)) { + CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); + goto set_ie; + } + + set_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status); + + CFGP2P_DBG(("enter\n")); + + ret = wl_cfgp2p_init_discovery(wl); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" init discovery error %d\n", ret)); + goto exit; + } + /* Set wsec to any non-zero value in the discovery bsscfg to ensure our + * P2P probe responses have the privacy bit set in the 802.11 WPA IE. + * Some peer devices may not initiate WPS with us if this bit is not set. + */ + ret = wl_cfgp2p_bssiovar_setint(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), + "wsec", wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), AES_ENABLED); + if (unlikely(ret < 0)) { + CFGP2P_ERR((" wsec error %d\n", ret)); + } +set_ie: + ret = wl_cfgp2p_set_managment_ie(wl, wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), + VNDR_IE_PRBREQ_FLAG, ie, ie_len); + + if (unlikely(ret < 0)) { + CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); + goto exit; + } +exit: + return ret; +} + +/* Disable P2P Discovery + * Parameters: + * @wl : wl_private_data + * Returns 0 if success. + */ +s32 +wl_cfgp2p_disable_discovery(struct wl_priv *wl) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" enter\n")); + clear_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status); + + if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { + CFGP2P_ERR((" do nothing, not initialized\n")); + goto exit; + } + + ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + + if (unlikely(ret < 0)) { + + CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); + } + /* Do a scan abort to stop the driver's scan engine in case it is still + * waiting out an action frame tx dwell time. + */ +#ifdef NOT_YET + if (test_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status)) { + p2pwlu_scan_abort(hdl, FALSE); + } +#endif + clear_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status); + ret = wl_cfgp2p_deinit_discovery(wl); + +exit: + return ret; +} + +s32 +wl_cfgp2p_escan(struct wl_priv *wl, u16 active, u32 num_chans, u16 *channels, + s32 search_state, u16 action, u32 bssidx) +{ + s32 ret = BCME_OK; + s32 memsize; + s32 eparams_size; + u32 i; + s8 *memblk; + wl_p2p_scan_t *p2p_params; + wl_escan_params_t *eparams; + wlc_ssid_t ssid; + /* Scan parameters */ +#define P2PAPI_SCAN_NPROBES 1 +#define P2PAPI_SCAN_DWELL_TIME_MS 40 +#define P2PAPI_SCAN_HOME_TIME_MS 10 + + set_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status); + /* Allocate scan params which need space for 3 channels and 0 ssids */ + eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + + OFFSETOF(wl_escan_params_t, params)) + + num_chans * sizeof(eparams->params.channel_list[0]); + + memsize = sizeof(wl_p2p_scan_t) + eparams_size; + memblk = scanparambuf; + if (memsize > sizeof(scanparambuf)) { + CFGP2P_ERR((" scanpar buf too small (%u > %u)\n", + memsize, sizeof(scanparambuf))); + return -1; + } + memset(memblk, 0, memsize); + memset(ioctlbuf, 0, sizeof(ioctlbuf)); + if (search_state == WL_P2P_DISC_ST_SEARCH) { + /* + * If we in SEARCH STATE, we don't need to set SSID explictly + * because dongle use P2P WILDCARD internally by default + */ + wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); + ssid.SSID_len = htod32(0); + + } else if (search_state == WL_P2P_DISC_ST_SCAN) { + /* SCAN STATE 802.11 SCAN + * WFD Supplicant has p2p_find command with (type=progressive, type= full) + * So if P2P_find command with type=progressive, + * we have to set ssid to P2P WILDCARD because + * we just do broadcast scan unless setting SSID + */ + strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID); + ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); + wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); + } + + + /* Fill in the P2P scan structure at the start of the iovar param block */ + p2p_params = (wl_p2p_scan_t*) memblk; + p2p_params->type = 'E'; + /* Fill in the Scan structure that follows the P2P scan structure */ + eparams = (wl_escan_params_t*) (p2p_params + 1); + eparams->params.bss_type = DOT11_BSSTYPE_ANY; + if (active) + eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; + else + eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; + + memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); + if (ssid.SSID_len) + memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); + + eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES); + eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); + eparams->params.active_time = htod32(-1); + eparams->params.passive_time = htod32(-1); + eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | + (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); + + for (i = 0; i < num_chans; i++) { + eparams->params.channel_list[i] = htodchanspec(channels[i]); + } + eparams->version = htod32(ESCAN_REQ_VERSION); + eparams->action = htod16(action); + eparams->sync_id = htod16(0x1234); + CFGP2P_INFO(("SCAN CHANNELS : ")); + + for (i = 0; i < num_chans; i++) { + if (i == 0) CFGP2P_INFO(("%d", channels[i])); + else CFGP2P_INFO((",%d", channels[i])); + } + + CFGP2P_INFO(("\n")); + + ret = wl_cfgp2p_bssiovar_setbuf(wl_to_p2p_bss_ndev(wl, bssidx), "p2p_scan", bssidx, + memblk, memsize, smbuf, sizeof(ioctlbuf)); + return ret; +} +/* Delete and Set a management ie to firmware + * Parameters: + * @wl : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, + * VNDR_IE_ASSOCREQ_FLAG) + * @ie : probe request ie (WPS IE + P2P IE) + * @ie_len : probe request ie length + * Returns 0 if success. + */ + +s32 +wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len) +{ + /* Vendor-specific Information Element ID */ +#define VNDR_SPEC_ELEMENT_ID 0xdd + s32 ret = BCME_OK; + u32 pos; + u8 *ie_buf; + u8 *mgmt_ie_buf; + u32 mgmt_ie_buf_len; + u32 *mgmt_ie_len; + u8 ie_id, ie_len; + u8 delete = 0; +#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) +#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) + + if (bssidx == P2PAPI_BSSCFG_PRIMARY) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = IE_TYPE(probe_req, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); + break; + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = IE_TYPE(probe_res, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); + break; + case VNDR_IE_ASSOCRSP_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = IE_TYPE(beacon, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return -1; + } + /* Add if there is any extra IE */ + if (p2p_ie && p2p_ie_len) { + CFGP2P_ERR(("Request has extra IE")); + if (p2p_ie_len > mgmt_ie_buf_len) { + CFGP2P_ERR(("extra IE size too big\n")); + ret = -ENOMEM; + } else { + if (mgmt_ie_buf != NULL) { + if ((p2p_ie_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, p2p_ie, p2p_ie_len) == 0)) { + CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); + goto exit; + } + pos = 0; + delete = 1; + ie_buf = (u8 *) mgmt_ie_buf; + while (pos < *mgmt_ie_len) { + ie_id = ie_buf[pos++]; + ie_len = ie_buf[pos++]; + CFGP2P_INFO(("DELELED ID(%d), Len(%d),\ + OUI(%02x:%02x:%02x)\n",\ + ie_id, ie_len, ie_buf[pos],\ + ie_buf[pos+1], ie_buf[pos+2])); + ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, + ie_buf+pos, VNDR_SPEC_ELEMENT_ID, + ie_buf+pos+3, ie_len-3, delete); + pos += ie_len; + } + + } + /* save the current IE in wl struct */ + memcpy(mgmt_ie_buf, p2p_ie, p2p_ie_len); + *mgmt_ie_len = p2p_ie_len; + pos = 0; + ie_buf = (u8 *) p2p_ie; + delete = 0; + while (pos < p2p_ie_len) { + ie_id = ie_buf[pos++]; + ie_len = ie_buf[pos++]; + CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI : %02x:%02x:%02x\n", + ie_id, ie_len, ie_buf[pos], ie_buf[pos+1], ie_buf[pos+2])); + ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, + VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete); + pos += ie_len; + } + } + + } +#undef IE_TYPE +#undef IE_TYPE_LEN +exit: + return ret; +} + +/* Clear the manament IE buffer of BSSCFG + * Parameters: + * @wl : wl_private data + * @bssidx : bssidx for BSS + * + * Returns 0 if success. + */ +s32 +wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) +{ +#define INIT_IE(IE_TYPE, BSS_TYPE) \ + do { \ + memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ + sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ + wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ + } while (0); + if (bssidx < 0) { + CFGP2P_ERR(("invalid bssidx\n")); + return BCME_BADARG; + } + INIT_IE(probe_req, bssidx); + INIT_IE(probe_res, bssidx); + INIT_IE(assoc_req, bssidx); + INIT_IE(assoc_res, bssidx); + INIT_IE(beacon, bssidx); + + + return BCME_OK; +} +/* Check whether pointed-to IE looks like WPA. */ +#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) +/* Check whether pointed-to IE looks like WPS. */ +#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) +/* Check whether the given IE looks like WFA P2P IE. */ +#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) + +/* Is any of the tlvs the expected entry? If + * not update the tlvs buffer pointer/length. + */ +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) +{ + /* If the contents match the OUI and the type */ + if (ie[TLV_LEN_OFF] >= oui_len + 1 && + !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && + type == ie[TLV_BODY_OFF + oui_len]) { + return TRUE; + } + + /* point to the next ie */ + ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; + /* calculate the length of the rest of the buffer */ + *tlvs_len -= (int)(ie - *tlvs); + /* update the pointer to the start of the buffer */ + *tlvs = ie; + + return FALSE; +} +wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { + return (wpa_ie_fixed_t *)ie; + } + } + return NULL; +} + +wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { + if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { + return (wifi_p2p_ie_t *)ie; + } + } + return NULL; +} + +static s32 +wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, + s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete) +{ + s32 err = BCME_OK; + s32 buf_len; + s32 iecount; + + vndr_ie_setbuf_t *ie_setbuf; + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { + CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1; + ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); + + CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len)); + if (!ie_setbuf) { + + CFGP2P_ERR(("Error allocating buffer for IE\n")); + return -ENOMEM; + } + if (delete) + strcpy(ie_setbuf->cmd, "del"); + else + strcpy(ie_setbuf->cmd, "add"); + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int)); + pktflag = htod32(pktflag); + memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, + &pktflag, sizeof(uint32)); + ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; + ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len + = (uchar)(data_len + VNDR_IE_MIN_LEN); + memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3); + memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len); + err = wl_cfgp2p_bssiovar_set(ndev, "vndr_ie", bssidx, ie_setbuf, buf_len); + CFGP2P_INFO(("vndr_ie iovar returns %d\n", err)); + kfree(ie_setbuf); + return err; +} + +/* + * Search the bssidx based on dev argument + * Parameters: + * @wl : wl_private data + * @ndev : net device to search bssidx + * Returns bssidx for ndev + */ +s32 +wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) +{ + u32 i; + s32 index = -1; + + if (ndev == NULL) { + CFGP2P_ERR((" ndev is NULL\n")); + goto exit; + } + for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { + if (ndev == wl_to_p2p_bss_ndev(wl, i)) { + index = wl_to_p2p_bss_bssidx(wl, i); + break; + } + } +exit: + return index; +} +/* + * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE + */ +s32 +wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + + CFGP2P_DBG((" Enter\n")); + /* TODO : have to acquire bottom half lock ? */ + if (test_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status) == 0) { + set_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status); + + if (wl->listen_timer) + del_timer_sync(wl->listen_timer); + + cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan, + wl->remain_on_chan_type, GFP_KERNEL); + } + + return ret; + +} + +/* + * Timer expire callback function for LISTEN + */ +static void +wl_cfgp2p_listen_expired(unsigned long data) +{ + struct wl_priv *wl = (struct wl_priv *) data; + + CFGP2P_DBG((" Enter\n")); + + if (test_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status) == 0) { + CFGP2P_ERR((" WLC_E_P2P_DISC_LISTEN_COMPLETE does not occur\n")); + set_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status); + + cfg80211_remain_on_channel_expired( + wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), + wl->cache_cookie, &wl->remain_on_chan, + wl->remain_on_chan_type, GFP_KERNEL); + } + +} + +/* + * Do a P2P Listen on the given channel for the given duration. + * A listen consists of sitting idle and responding to P2P probe requests + * with a P2P probe response. + * + * This fn assumes dongle p2p device discovery is already enabled. + * Parameters : + * @wl : wl_private data + * @channel : channel to listen + * @duration_ms : the time (milli seconds) to wait + */ +s32 +wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) +{ +#define INIT_TIMER(timer, func, duration, extra_delay) \ + do { \ + init_timer(timer); \ + timer->function = func; \ + timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ + timer->data = (unsigned long) wl; \ + add_timer(timer); \ + } while (0); + + s32 ret = BCME_OK; + CFGP2P_DBG((" Enter\n")); + if (unlikely(test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status) == 0)) { + + CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); + + ret = BCME_NOTREADY; + goto exit; + } + + clear_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status); + + wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + + if (wl->listen_timer) + del_timer_sync(wl->listen_timer); + + wl->listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + + if (wl->listen_timer == NULL) { + CFGP2P_ERR(("listen_timer allocation failed\n")); + return -ENOMEM; + } + + /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , + * otherwise we will wait up to duration_ms + 10ms + */ + INIT_TIMER(wl->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20); + +#undef INIT_TIMER +exit: + return ret; +} + + +s32 +wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 search_enable) +{ + s32 ret = BCME_OK; + CFGP2P_DBG((" Enter\n")); + if (!test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status)) { + + CFGP2P_ERR((" do nothing, discovery is off\n")); + return ret; + } + if (test_bit(WLP2P_STATUS_SEARCH_ENABLED, &wl->p2p_status) == search_enable) { + CFGP2P_ERR(("already : %d\n", search_enable)); + return ret; + } + + change_bit(WLP2P_STATUS_SEARCH_ENABLED, &wl->p2p_status); + /* When disabling Search, reset the WL driver's p2p discovery state to + * WL_P2P_DISC_ST_SCAN. + */ + if (!search_enable) { + clear_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status); + (void) wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); + } + + return ret; +} + +/* + * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE + */ +s32 +wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + s32 ret = BCME_OK; + u32 event_type = ntoh32(e->event_type); + + CFGP2P_DBG((" Enter\n")); + if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { + + CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received\n")); + + }else { + CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received\n")); + } + set_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status); + + wake_up_interruptible(&wl->dongle_event_wait); + + + return ret; +} +/* Send an action frame immediately without doing channel synchronization. + * + * This function does not wait for a completion event before returning. + * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action + * frame is transmitted. + * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an + * 802.11 ack has been received for the sent action frame. + */ +s32 +wl_cfgp2p_tx_action_frame(struct wl_priv *wl, wl_af_params_t *af_params, s32 bssidx) +{ + s32 ret = BCME_OK; + s32 timeout = 0; + + + CFGP2P_INFO(("\n")); + CFGP2P_INFO(("channel : %u , dwell time : %u\n", + af_params->channel, af_params->dwell_time)); + + clear_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status); +#define MAX_WAIT_TIME 2000 + if (bssidx == P2PAPI_BSSCFG_PRIMARY) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + + ret = wl_cfgp2p_bssiovar_setbuf(wl_to_p2p_bss_ndev(wl, bssidx), "actframe", + bssidx, af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf)); + if (ret < 0) { + + CFGP2P_ERR((" sending action frame is failed\n")); + goto exit; + } + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (test_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status) == TRUE), + msecs_to_jiffies(MAX_WAIT_TIME)); + + if (timeout > 0 && test_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status)) { + CFGP2P_INFO(("tx action frame operation is completed\n")); + ret = BCME_OK; + } else { + ret = BCME_ERROR; + CFGP2P_INFO(("tx action frame operation is failed\n")); + } +exit: + CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); +#undef MAX_WAIT_TIME + return ret; +} + +/* Generate our P2P Device Address and P2P Interface Address from our primary + * MAC address. + */ +void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, + struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) +{ + memset(out_dev_addr, 0, sizeof(*out_dev_addr)); + memset(out_int_addr, 0, sizeof(*out_int_addr)); + + /* Generate the P2P Device Address. This consists of the device's + * primary MAC address with the locally administered bit set. + */ + memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); + out_dev_addr->octet[0] |= 0x02; + + /* Generate the P2P Interface Address. If the discovery and connection + * BSSCFGs need to simultaneously co-exist, then this address must be + * different from the P2P Device Address. + */ + memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); + out_int_addr->octet[4] ^= 0x80; + +} + +/* P2P IF Address change to Virtual Interface MAC Address */ +void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) +{ + wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; + u16 len = ie->len; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + CFGP2P_DBG((" Enter\n")); + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + if (subelt_id == P2P_SEID_INTINTADDR) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device ID ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_DEV_INFO) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("Device ID ATTR FOUND\n")); + } + return; + } else { + CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); + } + subel += subelt_len; + } +} +/* + * Check if a BSS is up. + * This is a common implementation called by most OSL implementations of + * p2posl_bss_isup(). DO NOT call this function directly from the + * common code -- call p2posl_bss_isup() instead to allow the OSL to + * override the common implementation if necessary. + */ +bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) +{ + s32 result, val; + bool isup = false; + s8 getbuf[64]; + + /* Check if the BSS is up */ + *(int*)getbuf = -1; + result = wl_cfgp2p_iovar_getbuf_bss(ndev, "bss", &bsscfg_idx, + sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0); + if (result != 0) { + CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result)); + CFGP2P_ERR(("NOTE: this ioctl error is normal " + "when the BSS has not been created yet.\n")); + } else { + val = *(int*)getbuf; + val = dtoh32(val); + CFGP2P_INFO(("---wl bss -C %d ==> %d\n", bsscfg_idx, val)); + isup = (val ? TRUE : FALSE); + } + return isup; +} + + +/* Bring up or down a BSS */ +s32 +wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up) +{ + s32 ret = BCME_OK; + s32 val = up ? 1 : 0; + + struct { + s32 cfg; + s32 val; + } bss_setbuf; + + bss_setbuf.cfg = htod32(bsscfg_idx); + bss_setbuf.val = htod32(val); + CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); + ret = wl_cfgp2p_iovar_set_bss(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf)); + + if (ret != 0) { + CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); + } + + return ret; +} + +/* Check if 'p2p' is supported in the driver */ +s32 +wl_cfgp2p_is_p2p_supported(struct wl_priv *wl) +{ + s32 ret = BCME_OK; + s32 is_p2p_supported = 0; + ret = wl_cfgp2p_iovar_getint_bss(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY), "p2p", + &is_p2p_supported, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)); + if (ret < 0) { + CFGP2P_ERR(("wl p2p error %d\n", ret)); + return 0; + } + if (is_p2p_supported) + CFGP2P_INFO(("p2p is supported\n")); + + return is_p2p_supported; +} diff --git a/src/wl/sys/wl_cfgp2p.h b/src/wl/sys/wl_cfgp2p.h new file mode 100644 index 0000000..b208f25 --- /dev/null +++ b/src/wl/sys/wl_cfgp2p.h @@ -0,0 +1,131 @@ +/* + * Linux cfgp2p driver + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: wl_cfg80211.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $ + */ + +#ifndef _wl_cfgp2p_h_ +#define _wl_cfgp2p_h_ +#include <proto/802.11.h> +#include <proto/p2p.h> + +extern void +wl_cfgp2p_init_priv(struct wl_priv *wl); +extern s32 +wl_cfgp2p_set_firm_p2p(struct wl_priv *wl); +extern s32 +wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, + u32 channel, u16 listen_ms, int bssidx); +extern s32 +wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, + chanspec_t chspec); +extern s32 +wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); +extern s32 +wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); + +extern s32 +wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index); + +extern s32 +wl_cfgp2p_init_discovery(struct wl_priv *wl); +extern s32 +wl_cfgp2p_enable_discovery(struct wl_priv *wl, const u8 *ie, u32 ie_len); +extern s32 +wl_cfgp2p_disable_discovery(struct wl_priv *wl); +extern s32 +wl_cfgp2p_escan(struct wl_priv *wl, u16 active, u32 num_chans, u16 *channels, + s32 search_state, u16 action, u32 bssidx); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpaie(u8 *parse, u32 len); + +extern wpa_ie_fixed_t * +wl_cfgp2p_find_wpsie(u8 *parse, u32 len); + +extern wifi_p2p_ie_t * +wl_cfgp2p_find_p2pie(u8 *parse, u32 len); + +extern s32 +wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, + s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len); +extern s32 +wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); + +extern s32 +wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev); + + +extern s32 +wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +extern s32 +wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms); + +extern s32 +wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 search_enable); + +extern s32 +wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +extern s32 +wl_cfgp2p_tx_action_frame(struct wl_priv *wl, wl_af_params_t *af_params, s32 bssidx); + +extern void +wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, + struct ether_addr *out_int_addr); + +extern void +wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); + +extern s32 +wl_cfgp2p_bssiovar_set(struct net_device *dev, const s8 *iovar, s32 bssidx, + void *param, s32 paramlen); +extern s32 +wl_cfgp2p_bssiovar_get(struct net_device *dev, const s8 *iovar, s32 bssidx, + void *outbuf, s32 len); +extern s32 +wl_cfgp2p_bssiovar_setint(struct net_device *dev, const s8 *iovar, s32 bssidx, s32 val); +extern s32 +wl_cfgp2p_iovar_set_bss(struct net_device *dev, const s8 *iovar, void *param, s32 paramlen); +extern s32 +wl_cfgp2p_iovar_get_bss(struct net_device *dev, const s8 *iovar, void *outbuf, s32 len, s32 bssidx); + +extern bool +wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); + +extern s32 +wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up); + + +extern s32 +wl_cfgp2p_is_p2p_supported(struct wl_priv *wl); + +/* WiFi Direct */ +#define SOCIAL_CHAN_1 1 +#define SOCIAL_CHAN_2 6 +#define SOCIAL_CHAN_3 11 +#define WL_P2P_WILDCARD_SSID "DIRECT-" +#define WL_P2P_WILDCARD_SSID_LEN 7 +#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) +#endif /* _wl_cfgp2p_h_ */ diff --git a/src/wl/sys/wl_dbg.h b/src/wl/sys/wl_dbg.h new file mode 100644 index 0000000..0b99557 --- /dev/null +++ b/src/wl/sys/wl_dbg.h @@ -0,0 +1,49 @@ +/* + * Minimal debug/trace/assert driver definitions for + * Broadcom 802.11 Networking Adapter. + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * 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: wl_dbg.h,v 1.115.6.3 2010-12-15 21:42:23 Exp $ + */ + + + +#ifndef _wl_dbg_h_ +#define _wl_dbg_h_ + + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; + +#define WL_PRINT(args) printf args + + + +#define WL_NONE(args) + +#define WL_ERROR(args) +#define WL_TRACE(args) + + +extern uint32 wl_msg_level; +extern uint32 wl_msg_level2; +#endif diff --git a/src/wl/sys/wl_iw.c b/src/wl/sys/wl_iw.c index af8e03c..2493e98 100644 --- a/src/wl/sys/wl_iw.c +++ b/src/wl/sys/wl_iw.c @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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,9 +21,10 @@ * 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.8.6.58 2009/10/05 23:24:50 Exp $ + * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 Exp $ */ +#include <wlioctl.h> #include <typedefs.h> #include <linuxver.h> @@ -48,56 +49,103 @@ 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_SCAN(x) -#include <wl_iw.h> - -#ifdef BCMWAPI_WPI -#ifndef IW_ENCODE_ALG_SM4 -#define IW_ENCODE_ALG_SM4 0x20 +#ifdef PNO_SET_DEBUG +#define WL_PNO(x) printf x +#else +#define WL_PNO(x) #endif -#ifndef IW_AUTH_WAPI_ENABLED -#define IW_AUTH_WAPI_ENABLED 0x20 -#endif -#ifndef IW_AUTH_WAPI_VERSION_1 -#define IW_AUTH_WAPI_VERSION_1 0x00000008 -#endif +#define JF2MS ((((jiffies / HZ) * 1000) + ((jiffies % HZ) * 1000) / HZ)) -#ifndef IW_AUTH_CIPHER_SMS4 -#define IW_AUTH_CIPHER_SMS4 0x00000020 +#ifdef COEX_DBG +#define WL_TRACE_COEX(x) printf("TS:%lu ", JF2MS); \ + printf x +#else +#define WL_TRACE_COEX(x) #endif -#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK -#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 +#ifdef SCAN_DBG +#define WL_TRACE_SCAN(x) printf("TS:%lu ", JF2MS); \ + printf x +#else +#define WL_TRACE_SCAN(x) #endif -#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT -#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 -#endif -#endif -#include <linux/rtnetlink.h> +#include <wl_iw.h> + + +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) + +#include <linux/rtnetlink.h> + #define WL_IW_USE_ISCAN 1 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1 +#ifdef OEM_CHROMIUMOS +bool g_set_essid_before_scan = TRUE; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + struct mutex g_wl_ss_scan_lock; +#endif + +#if defined(SOFTAP) +#define WL_SOFTAP(x) +static struct net_device *priv_dev; +static bool ap_cfg_running = FALSE; +bool ap_fw_loaded = FALSE; +struct net_device *ap_net_dev = NULL; +tsk_ctl_t ap_eth_ctl; +static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap); +static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac); +#endif + + #define WL_IW_IOCTL_CALL(func_call) \ do { \ func_call; \ } while (0) +#define RETURN_IF_EXTRA_NULL(extra) \ + if (!extra) { \ + WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \ + return -EINVAL; \ + } + static int g_onoff = G_WLAN_SET_ON; +wl_iw_extra_params_t g_wl_iw_params; + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + +static struct mutex wl_start_lock; +static struct mutex wl_cache_lock; +static struct mutex wl_softap_lock; + +#define DHD_OS_MUTEX_INIT(a) mutex_init(a) +#define DHD_OS_MUTEX_LOCK(a) mutex_lock(a) +#define DHD_OS_MUTEX_UNLOCK(a) mutex_unlock(a) + +#else + +#define DHD_OS_MUTEX_INIT(a) +#define DHD_OS_MUTEX_LOCK(a) +#define DHD_OS_MUTEX_UNLOCK(a) + +#endif -extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, - uint32 reason, char* stringBuf, uint buflen); #include <bcmsdbus.h> extern void dhd_customer_gpio_wlan_ctrl(int onoff); extern uint dhd_dev_reset(struct net_device *dev, uint8 flag); @@ -108,22 +156,12 @@ uint wl_msg_level = WL_ERROR_VAL; #define MAX_WLIW_IOCTL_LEN 1024 -#if defined(IL_BIGENDIAN) -#include <bcmendian.h> -#define htod32(i) (bcmswap32(i)) -#define htod16(i) (bcmswap16(i)) -#define dtoh32(i) (bcmswap32(i)) -#define dtoh16(i) (bcmswap16(i)) -#define htodchanspec(i) htod16(i) -#define dtohchanspec(i) dtoh16(i) -#else #define htod32(i) i #define htod16(i) i #define dtoh32(i) i #define dtoh16(i) i #define htodchanspec(i) i #define dtohchanspec(i) i -#endif #ifdef CONFIG_WIRELESS_EXT @@ -137,12 +175,18 @@ 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; - +bool btcoex_is_sco_active(struct net_device *dev); +static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; +#if defined(CONFIG_FIRST_SCAN) +static volatile uint g_first_broadcast_scan; +static volatile uint g_first_counter_scans; +#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3 +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define DAEMONIZE(a) daemonize(a); \ @@ -158,7 +202,14 @@ wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; #endif #if defined(WL_IW_USE_ISCAN) - +#if !defined(CSCAN) +static void wl_iw_free_ss_cache(void); +static int wl_iw_run_ss_cache_timer(int kick_off); +#endif +#if defined(CONFIG_FIRST_SCAN) +int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); +#endif +static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len); #define ISCAN_STATE_IDLE 0 #define ISCAN_STATE_SCANING 1 @@ -179,16 +230,38 @@ typedef struct iscan_info { iscan_buf_t * list_cur; - long sysioc_pid; - struct semaphore sysioc_sem; - struct completion sysioc_exited; + tsk_ctl_t tsk_ctl; uint32 scan_flag; - +#if defined CSCAN + char ioctlbuf[WLC_IOCTL_MEDLEN]; +#else char ioctlbuf[WLC_IOCTL_SMLEN]; +#endif + + wl_iscan_params_t *iscan_ex_params_p; + int iscan_ex_param_size; } iscan_info_t; -#define COEX_DHCP 1 + + + +#define COEX_DHCP 1 #ifdef COEX_DHCP + +#define BT_DHCP_eSCO_FIX +#define BT_DHCP_USE_FLAGS +#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500 +#define BT_DHCP_FLAG_FORCE_TIME 5500 + + + +static int wl_iw_set_btcoex_dhcp( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +); + static void wl_iw_bt_flag_set(struct net_device *dev, bool set); static void wl_iw_bt_release(void); @@ -198,31 +271,34 @@ typedef enum bt_coex_status { BT_DHCP_OPPORTUNITY_WINDOW, BT_DHCP_FLAG_FORCE_TIMEOUT } coex_status_t; -#define BT_DHCP_OPPORTUNITY_WINDOW_TIEM 2500 -#define BT_DHCP_FLAG_FORCE_TIME 5500 + typedef struct bt_info { struct net_device *dev; struct timer_list timer; uint32 timer_ms; uint32 timer_on; + uint32 ts_dhcp_start; + uint32 ts_dhcp_ok; + bool dhcp_done; int bt_state; - long bt_pid; - struct semaphore bt_sem; - struct completion bt_exited; + tsk_ctl_t tsk_ctl; + } bt_info_t; bt_info_t *g_bt = NULL; static void wl_iw_bt_timerfunc(ulong data); #endif iscan_info_t *g_iscan = NULL; +void dhd_print_buf(void *pbuf, int len, int bytes_per_line); static void wl_iw_timerfunc(ulong data); static void wl_iw_set_event_mask(struct net_device *dev); static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); #endif + static int wl_iw_set_scan( struct net_device *dev, @@ -230,6 +306,8 @@ wl_iw_set_scan( union iwreq_data *wrqu, char *extra ); + +#ifndef CSCAN static int wl_iw_get_scan( struct net_device *dev, @@ -243,12 +321,13 @@ wl_iw_get_scan_prep( wl_scan_results_t *list, struct iw_request_info *info, char *extra, - __u16 max_size + short max_size ); +#endif - -static void swap_key_from_BE( - wl_wsec_key_t *key +static void +swap_key_from_BE( + wl_wsec_key_t *key ) { key->index = htod32(key->index); @@ -260,8 +339,9 @@ static void swap_key_from_BE( key->iv_initialized = htod32(key->iv_initialized); } -static void swap_key_to_BE( - wl_wsec_key_t *key +static void +swap_key_to_BE( + wl_wsec_key_t *key ) { key->index = dtoh32(key->index); @@ -284,23 +364,49 @@ dev_wlc_ioctl( struct ifreq ifr; wl_ioctl_t ioc; mm_segment_t fs; - int ret; + int ret = -EINVAL; + + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return ret; + } - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; + net_os_wake_lock(dev); - strcpy(ifr.ifr_name, dev->name); - ifr.ifr_data = (caddr_t) &ioc; + WL_INFORM(("%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", + __FUNCTION__, current->pid, cmd, arg, len)); - - dev_open(dev); + if (g_onoff == G_WLAN_SET_ON) { + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t) &ioc; + + + ret = dev_open(dev); + if (ret) { + WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret)); + net_os_wake_unlock(dev); + return ret; + } + + fs = get_fs(); + set_fs(get_ds()); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31) + 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 : ignored\n", __FUNCTION__)); + } - fs = get_fs(); - set_fs(get_ds()); - ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); - set_fs(fs); + net_os_wake_unlock(dev); return ret; } @@ -329,6 +435,23 @@ dev_wlc_intvar_get_reg( } +static int +dev_wlc_intvar_set_reg( + struct net_device *dev, + char *name, + char *addr, + char * val) +{ + char reg_addr[8]; + + memset(reg_addr, 0, sizeof(reg_addr)); + memcpy((char *)®_addr[0], (char *)addr, 4); + memcpy((char *)®_addr[4], (char *)val, 4); + + return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); +} + + static int @@ -362,6 +485,9 @@ dev_iw_iovar_setbuf( iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ASSERT(iolen); + if (iolen == 0) + return 0; + return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); } @@ -391,7 +517,11 @@ dev_wlc_bufvar_set( char *name, char *buf, int len) { - char ioctlbuf[WLC_IOCTL_SMLEN]; +#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)); @@ -399,7 +529,7 @@ dev_wlc_bufvar_set( return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen)); } -#endif +#endif static int @@ -408,9 +538,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)); @@ -508,6 +641,37 @@ wl_iw_set_passive_scan( return error; } + +static int +wl_iw_set_txpower( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = 0; + char *p = extra; + int txpower = -1; + + txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1); + if ((txpower >= 0) && (txpower <= 127)) + { + txpower |= WL_TXPWR_OVERRIDE; + txpower = htod32(txpower); + + error = dev_wlc_intvar_set(dev, "qtxpower", txpower); + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower)); + } else { + WL_ERROR(("%s: set tx power failed\n", __FUNCTION__)); + p += snprintf(p, MAX_WX_STRING, "FAIL"); + } + + wrqu->data.length = p - extra + 1; + return error; +} + static int wl_iw_get_macaddr( struct net_device *dev, @@ -534,6 +698,7 @@ wl_iw_get_macaddr( } + static int wl_iw_set_country( struct net_device *dev, @@ -547,8 +712,13 @@ wl_iw_set_country( char *p = extra; int country_offset; int country_code_size; + wl_country_t cspec = {{0}, 0, {0}}; + char smbuf[WLC_IOCTL_SMLEN]; + scb_val_t scbval; + cspec.rev = -1; memset(country_code, 0, sizeof(country_code)); + memset(smbuf, 0, sizeof(smbuf)); country_offset = strcspn(extra, " "); @@ -560,15 +730,32 @@ wl_iw_set_country( MIN(country_code_size, sizeof(country_code))); - if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY, - &country_code, sizeof(country_code))) >= 0) { + bzero(&scbval, sizeof(scb_val_t)); + if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) { + WL_ERROR(("%s: set country failed due to Disassoc error\n", __FUNCTION__)); + goto exit_failed; + } + + memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); + memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); + + get_customized_country_code((char *)&cspec.country_abbrev, &cspec); + + + if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec, + sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) { p += snprintf(p, MAX_WX_STRING, "OK"); - WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code)); + WL_ERROR(("%s: set country for %s as %s rev %d is OK\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + dhd_bus_country_set(dev, &cspec); goto exit; } } - WL_ERROR(("%s: set country %s failed code %d\n", __FUNCTION__, country_code, error)); + WL_ERROR(("%s: set country for %s as %s rev %d failed\n", + __FUNCTION__, country_code, cspec.ccode, cspec.rev)); + +exit_failed: p += snprintf(p, MAX_WX_STRING, "FAIL"); exit: @@ -576,6 +763,234 @@ exit: return error; } +#ifdef CONFIG_MACH_MAHIMAHI +static int +wl_iw_set_power_mode( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = 0; + char *p = extra; + static int pm = PM_FAST; + int pm_local = PM_OFF; + char powermode_val = 0; + + WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra)); + + strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1); + + if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { + + WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); + + dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)); + dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); + + + net_os_set_packet_filter(dev, 0); + +#ifdef COEX_DHCP + g_bt->ts_dhcp_start = JF2MS; + g_bt->dhcp_done = false; + WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n", + __FUNCTION__, pm, pm_local)); + +#endif + } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { + + + dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); + + + net_os_set_packet_filter(dev, 1); + +#ifdef COEX_DHCP + g_bt->dhcp_done = true; + g_bt->ts_dhcp_ok = JF2MS; + WL_TRACE_COEX(("%s: DHCP done for:%d ms, restored pm:%d\n", + __FUNCTION__, (g_bt->ts_dhcp_ok - g_bt->ts_dhcp_start), pm)); +#endif + + } else { + WL_ERROR(("%s Unkwown yet power setting, ignored\n", + __FUNCTION__)); + } + + p += snprintf(p, MAX_WX_STRING, "OK"); + + wrqu->data.length = p - extra + 1; + + return error; +} +#endif + + +bool btcoex_is_sco_active(struct net_device *dev) +{ + int ioc_res = 0; + bool res = false; + int sco_id_cnt = 0; + int param27; + int i; + + for (i = 0; i < 12; i++) { + + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); + + WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n", + __FUNCTION__, i, param27)); + + if (ioc_res < 0) { + WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__)); + break; + } + + if ((param27 & 0x6) == 2) { + sco_id_cnt++; + } + + if (sco_id_cnt > 2) { + WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", + __FUNCTION__, sco_id_cnt, i)); + res = true; + break; + } + + msleep(5); + } + + return res; +} + +#if defined(BT_DHCP_eSCO_FIX) + +static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +{ + static bool saved_status = false; + + char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; + char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + + uint32 regaddr; + static uint32 saved_reg50; + static uint32 saved_reg51; + static uint32 saved_reg64; + static uint32 saved_reg65; + static uint32 saved_reg71; + + if (trump_sco) { + + + WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n")); + + + if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { + + saved_status = TRUE; + WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:" + " 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __FUNCTION__, saved_reg50, saved_reg51, + saved_reg64, saved_reg65, saved_reg71)); + + } else { + WL_ERROR((":%s: save btc_params failed\n", + __FUNCTION__)); + saved_status = false; + return -1; + } + + WL_TRACE_COEX(("override with [50,51,64,65,71]:" + " 0x%x 0x%x 0x%x 0x%x 0x%x\n", + *(u32 *)(buf_reg50va_dhcp_on+4), + *(u32 *)(buf_reg51va_dhcp_on+4), + *(u32 *)(buf_reg64va_dhcp_on+4), + *(u32 *)(buf_reg65va_dhcp_on+4), + *(u32 *)(buf_reg71va_dhcp_on+4))); + + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8); + + saved_status = true; + + } else if (saved_status) { + + WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n")); + + regaddr = 50; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg50); + regaddr = 51; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg51); + regaddr = 64; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg64); + regaddr = 65; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg65); + regaddr = 71; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg71); + + WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, saved_reg64, + saved_reg65, saved_reg71)); + + saved_status = false; + } else { + WL_ERROR((":%s att to restore not saved BTCOEX params\n", + __FUNCTION__)); + return -1; + } + return 0; +} +#endif + + +#ifdef CONFIG_MACH_MAHIMAHI +static int +wl_iw_get_power_mode( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = 0; + int pm_local; + char *p = extra; + + error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local)); + if (!error) { + WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local)); + if (pm_local == PM_OFF) + pm_local = 1; + else + pm_local = 0; + p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local); + } + else { + WL_TRACE(("%s: Error = %d\n", __func__, error)); + p += snprintf(p, MAX_WX_STRING, "FAIL"); + } + wrqu->data.length = p - extra + 1; + return error; +} +#endif + static int wl_iw_set_btcoex_dhcp( struct net_device *dev, @@ -586,78 +1001,138 @@ wl_iw_set_btcoex_dhcp( { int error = 0; char *p = extra; - uint val; +#ifndef CONFIG_MACH_MAHIMAHI + static int pm = PM_FAST; + int pm_local = PM_OFF; +#endif char powermode_val = 0; char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - char buf_reg66val_defualt[8] = { 66, 00, 00, 00, 0x88, 0x13, 0x00, 0x00 }; - char buf_reg41val_defualt[8] = { 41, 00, 00, 00, 0x13, 0x00, 0x00, 0x00 }; - char buf_reg68val_defualt[8] = { 68, 00, 00, 00, 0x14, 0x00, 0x00, 0x00 }; + uint32 regaddr; + static uint32 saved_reg66; + static uint32 saved_reg41; + static uint32 saved_reg68; + static bool saved_status = FALSE; #ifdef COEX_DHCP char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; #endif +#ifdef CONFIG_MACH_MAHIMAHI + strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") +1, 1); +#else strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1); - - - dev_wlc_intvar_get_reg(dev, "btc_params", 68, &val); +#endif if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg66va_dhcp_on[0], sizeof(buf_reg66va_dhcp_on)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg41va_dhcp_on[0], sizeof(buf_reg41va_dhcp_on)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on)); + if ((saved_status == FALSE) && +#ifndef CONFIG_MACH_MAHIMAHI + (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) && +#endif + (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { + saved_status = TRUE; + WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + +#ifndef CONFIG_MACH_MAHIMAHI + dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local)); +#endif + + #ifdef COEX_DHCP - - g_bt->bt_state = BT_DHCP_START; - g_bt->timer_on = 1; - add_timer(&g_bt->timer); - WL_TRACE(("%s enable BT DHCP Timer\n", __FUNCTION__)); + + if (btcoex_is_sco_active(dev)) { + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg66va_dhcp_on[0], + sizeof(buf_reg66va_dhcp_on)); + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg41va_dhcp_on[0], + sizeof(buf_reg41va_dhcp_on)); + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg68va_dhcp_on[0], + sizeof(buf_reg68va_dhcp_on)); + saved_status = TRUE; + + g_bt->bt_state = BT_DHCP_START; + g_bt->timer_on = 1; + mod_timer(&g_bt->timer, g_bt->timer.expires); + WL_TRACE_COEX(("%s enable BT DHCP Timer\n", + __FUNCTION__)); + } #endif - + } + else if (saved_status == TRUE) { + WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); + } } +#ifdef CONFIG_MACH_MAHIMAHI + else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { +#else else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) { +#endif - WL_TRACE(("%s: DHCP session done\n", __FUNCTION__)); + + +#ifndef CONFIG_MACH_MAHIMAHI + dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); +#endif #ifdef COEX_DHCP WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); if (g_bt->timer_on) { - del_timer(&g_bt->timer); g_bt->timer_on = 0; + del_timer_sync(&g_bt->timer); + + if (g_bt->bt_state != BT_DHCP_IDLE) { + + WL_TRACE_COEX(("%s bt->bt_state:%d\n", + __FUNCTION__, g_bt->bt_state)); + + up(&g_bt->tsk_ctl.sema); + } } - dev_wlc_bufvar_set(dev, "btc_flags", \ + if (saved_status == TRUE) + dev_wlc_bufvar_set(dev, "btc_flags", (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); #endif - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg66val_defualt[0], sizeof(buf_reg66val_defualt)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg41val_defualt[0], sizeof(buf_reg41val_defualt)); - - dev_wlc_bufvar_set(dev, "btc_params", \ - (char *)&buf_reg68val_defualt[0], sizeof(buf_reg68val_defualt)); + if (saved_status == TRUE) { + regaddr = 66; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg66); + regaddr = 41; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg41); + regaddr = 68; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg68); + + WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + } + saved_status = FALSE; + } else { - WL_ERROR(("Unkwown yet power setting, ignored\n")); + WL_ERROR(("%s Unkwown yet power setting, ignored\n", + __FUNCTION__)); } p += snprintf(p, MAX_WX_STRING, "OK"); @@ -667,7 +1142,38 @@ wl_iw_set_btcoex_dhcp( return error; } -int +static int +wl_iw_set_suspend( +struct net_device *dev, +struct iw_request_info *info, +union iwreq_data *wrqu, +char *extra +) +{ + int suspend_flag; + int ret_now; + int ret = 0; + + suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now))) + WL_ERROR(("%s: Suspend Flag %d -> %d\n", + __FUNCTION__, ret_now, suspend_flag)); + else + WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } + + return ret; +} + +static int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) { int i, c; @@ -704,6 +1210,7 @@ wl_iw_get_link_speed( static int link_speed; + net_os_wake_lock(dev); if (g_onoff == G_WLAN_SET_ON) { error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed)); link_speed *= 500000; @@ -713,9 +1220,373 @@ wl_iw_get_link_speed( wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_get_dtim_skip( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + char iovbuf[32]; + + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { + + memset(iovbuf, 0, sizeof(iovbuf)); + strcpy(iovbuf, "bcn_li_dtim"); + + if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR, + &iovbuf, sizeof(iovbuf))) >= 0) { + + p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]); + WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0])); + wrqu->data.length = p - extra + 1; + } + else + WL_ERROR(("%s: get dtim_skip failed code %d\n", + __FUNCTION__, error)); + } + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_set_dtim_skip( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + int bcn_li_dtim; + char iovbuf[32]; + + net_os_wake_lock(dev); + if (g_onoff == G_WLAN_SET_ON) { + + bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0'); + + if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) { + + memset(iovbuf, 0, sizeof(iovbuf)); + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR, + &iovbuf, sizeof(iovbuf))) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + + + net_os_set_dtim_skip(dev, bcn_li_dtim); + + WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, + bcn_li_dtim)); + goto exit; + } + else WL_ERROR(("%s: set dtim_skip %d failed code %d\n", + __FUNCTION__, bcn_li_dtim, error)); + } + else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", + __FUNCTION__, bcn_li_dtim)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_get_band( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + static int band; + + net_os_wake_lock(dev); + + if (g_onoff == G_WLAN_SET_ON) { + error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band)); + + p += snprintf(p, MAX_WX_STRING, "Band %d", band); + + wrqu->data.length = p - extra + 1; + } + + net_os_wake_unlock(dev); + return error; +} + + +static int +wl_iw_set_band( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + uint band; + + net_os_wake_lock(dev); + + if (g_onoff == G_WLAN_SET_ON) { + + band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0'); + + if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { + + if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND, + &band, sizeof(band))) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band)); + goto exit; + } else { + WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, + band, error)); + } + } else { + WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band)); + } + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + +#ifdef PNO_SUPPORT + +static int +wl_iw_set_pno_reset( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + + net_os_wake_lock(dev); + if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { + + if ((error = dhd_dev_pno_reset(dev)) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set OK\n", __FUNCTION__)); + goto exit; + } + else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); + return error; +} + + + +static int +wl_iw_set_pno_enable( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int error = -1; + char *p = extra; + int pfn_enabled; + + net_os_wake_lock(dev); + pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0'); + + if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) { + + if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) { + p += snprintf(p, MAX_WX_STRING, "OK"); + WL_TRACE(("%s: set OK\n", __FUNCTION__)); + goto exit; + } + else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error)); + } + + p += snprintf(p, MAX_WX_STRING, "FAIL"); + +exit: + wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } + + +static int +wl_iw_set_pno_set( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int res = -1; + wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + int nssid = 0; + cmd_tlv_t *cmd_tlv_temp; + char *str_ptr; + int tlv_size_left; + int pno_time; + int pno_repeat; + int pno_freq_expo_max; +#ifdef PNO_SET_DEBUG + int i; + char pno_in_example[] = { + 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', + 'S', '1', '2', '0', + 'S', + 0x04, + 'B', 'R', 'C', 'M', + 'S', + 0x04, + 'G', 'O', 'O', 'G', + 'T', + '1', 'E', + 'R', + '2', + 'M', + '2', + 0x00 + }; +#endif + + net_os_wake_lock(dev); + WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + goto exit_proc; + } + + if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) { + WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, + wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))); + goto exit_proc; + } + +#ifdef PNO_SET_DEBUG + if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) { + res = -ENOMEM; + goto exit_proc; + } + memcpy(extra, pno_in_example, sizeof(pno_in_example)); + wrqu->data.length = sizeof(pno_in_example); + for (i = 0; i < wrqu->data.length; i++) + printf("%02X ", extra[i]); + printf("\n"); +#endif + + str_ptr = extra; +#ifdef PNO_SET_DEBUG + str_ptr += strlen("PNOSETUP "); + tlv_size_left = wrqu->data.length - strlen("PNOSETUP "); +#else + str_ptr += strlen(PNOSETUP_SET_CMD); + tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD); +#endif + + cmd_tlv_temp = (cmd_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + pno_repeat = pno_freq_expo_max = 0; + + if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && + (cmd_tlv_temp->version == PNO_TLV_VERSION) && + (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) + { + str_ptr += sizeof(cmd_tlv_t); + tlv_size_left -= sizeof(cmd_tlv_t); + + + if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, + MAX_PFN_LIST_COUNT, + &tlv_size_left)) <= 0) { + WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } + else { + if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { + WL_ERROR(("%s scan duration corrupted field size %d\n", + __FUNCTION__, tlv_size_left)); + goto exit_proc; + } + str_ptr++; + pno_time = simple_strtoul(str_ptr, &str_ptr, 16); + WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); + + + if (str_ptr[0] != 0) { + if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { + WL_ERROR(("%s pno repeat : corrupted field\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); + WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); + if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { + WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", + __FUNCTION__)); + goto exit_proc; + } + str_ptr++; + pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); + WL_PNO(("%s: pno_freq_expo_max=%d\n", + __FUNCTION__, pno_freq_expo_max)); + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + + res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); + +exit_proc: + net_os_wake_unlock(dev); + return res; +} +#endif + static int wl_iw_get_rssi( struct net_device *dev, @@ -725,36 +1596,40 @@ 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; + net_os_wake_lock(dev); + + 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)); + if (error) { + WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error)); + net_os_wake_unlock(dev); + return error; + } rssi = dtoh32(scb_val.val); error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); - - ssid.SSID_len = dtoh32(ssid.SSID_len); - } - - if (!ssid.SSID_len) { - return 0; + if (!error) { + ssid.SSID_len = dtoh32(ssid.SSID_len); + wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); + } } - wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len)); p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi); wrqu->data.length = p - extra + 1; + net_os_wake_unlock(dev); return error; } -static int +int wl_iw_send_priv_event( struct net_device *dev, char *flag @@ -772,137 +1647,541 @@ wl_iw_send_priv_event( strcpy(extra, flag); wrqu.data.length = strlen(extra); wireless_send_event(dev, cmd, &wrqu, extra); + net_os_wake_lock_timeout_enable(dev); WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); return 0; } -static int -_wl_control_sysioc_thread_wl_off(void *data) + +int +wl_control_wl_start(struct net_device *dev) { - struct wl_ctrl *wl_ctl = (struct wl_ctrl *)data; + int ret = 0; + + WL_TRACE(("Enter %s \n", __FUNCTION__)); + + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } + + DHD_OS_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 + + ret = dhd_dev_reset(dev, 0); + +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 1); +#endif + + dhd_dev_init_ioctl(dev); - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(wl_ctl->dev); + g_onoff = G_WLAN_SET_ON; + } + WL_ERROR(("Exited %s \n", __FUNCTION__)); + + DHD_OS_MUTEX_UNLOCK(&wl_start_lock); + return ret; +} - DAEMONIZE("wlcontrol_sysioc"); - WL_TRACE(("%s Entered\n", __FUNCTION__)); +static int +wl_iw_control_wl_off( + struct net_device *dev, + struct iw_request_info *info +) +{ + int ret = 0; + + WL_TRACE(("Enter %s\n", __FUNCTION__)); - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_OFF, "sysioc_thread_wl_off"); - WAKE_LOCK(iw->pub, WAKE_LOCK_OFF); + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } - while (down_interruptible(&wl_ctl->timer_sem) == 0) { + DHD_OS_MUTEX_LOCK(&wl_start_lock); - WL_TRACE(("%s Turning off wifi dev\n", __FUNCTION__)); +#ifdef SOFTAP + ap_cfg_running = FALSE; +#endif + if (g_onoff == G_WLAN_SET_ON) { g_onoff = G_WLAN_SET_OFF; #if defined(WL_IW_USE_ISCAN) g_iscan->iscan_state = ISCAN_STATE_IDLE; -#endif +#endif - dhd_dev_reset(wl_ctl->dev, 1); + dhd_dev_reset(dev, 1); + +#if defined(WL_IW_USE_ISCAN) +#if !defined(CSCAN) + + wl_iw_free_ss_cache(); + wl_iw_run_ss_cache_timer(0); + + g_ss_cache_ctrl.m_link_down = 1; +#endif + memset(g_scan, 0, G_SCAN_RESULTS); + g_scan_specified_ssid = 0; +#if defined(CONFIG_FIRST_SCAN) + + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; + g_first_counter_scans = 0; +#endif +#endif #if defined(BCMLXSDMMC) sdioh_stop(NULL); #endif - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); + + net_os_set_dtim_skip(dev, 0); - wl_iw_send_priv_event(wl_ctl->dev, "STOP"); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); - break; + wl_iw_send_priv_event(dev, "STOP"); } - WL_TRACE(("%s Exited\n", __FUNCTION__)); + DHD_OS_MUTEX_UNLOCK(&wl_start_lock); - WAKE_UNLOCK(iw->pub, WAKE_LOCK_OFF); - WAKE_LOCK_DESTROY(iw->pub, WAKE_LOCK_OFF); + WL_TRACE(("Exited %s\n", __FUNCTION__)); - complete_and_exit(&wl_ctl->sysioc_exited, 0); - KILL_PROC(wl_ctl->sysioc_pid, SIGTERM); + return ret; } -static void -wl_iw_stop_timerfunc(ulong data) +static int +wl_iw_control_wl_on( + struct net_device *dev, + struct iw_request_info *info +) { - struct wl_ctrl * wl_ctl = (struct wl_ctrl *)data; + int ret = 0; - WL_TRACE(("%s\n", __FUNCTION__)); + WL_TRACE(("Enter %s \n", __FUNCTION__)); - del_timer(wl_ctl->timer); + ret = wl_control_wl_start(dev); - up(&wl_ctl->timer_sem); + wl_iw_send_priv_event(dev, "START"); + +#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, void *buf); + +#define PTYPE_STRING 0 +#define PTYPE_INTDEC 1 +#define PTYPE_INTHEX 2 +#define PTYPE_STR_HEX 3 + +static int get_parameter_from_string( + char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); + +#endif + static int -wl_iw_control_wl_off( - struct net_device *dev, - struct iw_request_info *info -) +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; +} + + + +static 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 +static 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; - static struct wl_ctrl ctl; - static struct timer_list timer; - WL_TRACE(("Enter %s\n", __FUNCTION__)); + memset(sub_cmd, 0, sizeof(sub_cmd)); + memset(ap_cfg, 0, sizeof(struct ap_profile)); + if (get_parameter_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_parameter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN); + + ret |= get_parameter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN); + + ret |= get_parameter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN); + + ret |= get_parameter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5); + - ctl.timer = &timer; - ctl.dev = dev; - sema_init(&ctl.timer_sem, 0); - init_completion(&ctl.sysioc_exited); + get_parameter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5); - ctl.sysioc_pid = kernel_thread(_wl_control_sysioc_thread_wl_off, &ctl, 0); + get_parameter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5); - timer.data = (ulong)&ctl; - timer.function = wl_iw_stop_timerfunc; - init_timer(&timer); - timer.expires = jiffies + 2000 * HZ / 1000; - add_timer(&timer); + + get_parameter_from_string(&str_ptr, "HIDDEN=", + PTYPE_INTDEC, &ap_cfg->closednet, 5); - WL_TRACE(("Exited %s\n", __FUNCTION__)); + + get_parameter_from_string(&str_ptr, "COUNTRY=", + PTYPE_STRING, &ap_cfg->country_code, 3); return ret; } +#endif + + +#ifdef SOFTAP static int -wl_iw_control_wl_on( - struct net_device *dev, - struct iw_request_info *info -) +iwpriv_set_ap_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) { - int ret = 0; + int res = 0; + char *extra = NULL; + struct ap_profile *ap_cfg = &my_ap; - WL_TRACE(("Enter %s \n", __FUNCTION__)); + 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 (g_onoff == G_WLAN_SET_OFF) { - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); + if (wrqu->data.length != 0) { -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 0); -#endif + char *str_ptr; - dhd_dev_reset(dev, 0); + if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) + return -ENOMEM; -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 1); -#endif + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + kfree(extra); + return -EFAULT; + } - dhd_dev_init_ioctl(dev); + extra[wrqu->data.length] = 0; + WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra)); - g_onoff = G_WLAN_SET_ON; + memset(ap_cfg, 0, sizeof(struct ap_profile)); + + + + str_ptr = extra; + + if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) { + WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res)); + kfree(extra); + return -1; + } + + } else { + + WL_ERROR(("IWPRIV argument len = 0 \n")); + return -1; } - wl_iw_send_priv_event(dev, "START"); + if ((res = set_ap_cfg(dev, ap_cfg)) < 0) + WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res)); - WL_TRACE(("Exited %s \n", __FUNCTION__)); + 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[384]; + char *p_mac_str; + char *p_mac_str_end; + wl_iw_t *iw; + + if ((!dev) || (!extra)) { + + return -EINVAL; + } + + iw = *(wl_iw_t **)netdev_priv(dev); + + MUTEX_LOCK_SOFTAP_SET(iw->pub); + DHD_OS_WAKE_LOCK(iw->pub); + + 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)); + + memset(sta_maclist, 0, sizeof(mac_buf)); + + sta_maclist->count = 8; + + WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n", + __FUNCTION__, dev->name, sizeof(mac_buf))); + + if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) { + WL_ERROR(("%s: sta list ioctl error:%d\n", + __FUNCTION__, ret)); + goto func_exit; + } + + WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__, + sta_maclist->count)); + + + memset(mac_lst, 0, sizeof(mac_lst)); + p_mac_str = mac_lst; + p_mac_str_end = &mac_lst[sizeof(mac_lst)-1]; + + for (i = 0; i < 8; i++) { + struct ether_addr * id = &sta_maclist->ea[i]; + if (!ETHER_ISNULLADDR(id->octet)) { + scb_val_t scb_val; + int rssi = 0; + bzero(&scb_val, sizeof(scb_val_t)); + + + if ((p_mac_str_end - p_mac_str) <= 36) { + WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n", + __FUNCTION__, i)); + break; + } + + p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, + "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i, + id->octet[0], id->octet[1], id->octet[2], + id->octet[3], id->octet[4], id->octet[5]); + + + bcopy(id->octet, &scb_val.ea, 6); + ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); + if (ret < 0) { + snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR"); + WL_ERROR(("%s: RSSI ioctl error:%d\n", + __FUNCTION__, ret)); + break; + } + + rssi = dtoh32(scb_val.val); + p_mac_str += snprintf(p_mac_str, MAX_WX_STRING, + "RSSI:%d", rssi); + } + } + + p_iwrq->data.length = strlen(mac_lst)+1; + + WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__, + mac_lst, p_iwrq->data.pointer)); + + if (p_iwrq->data.length) { + bcopy(mac_lst, extra, p_iwrq->data.length); + } + +func_exit: + DHD_OS_WAKE_UNLOCK(iw->pub); + MUTEX_UNLOCK_SOFTAP_SET(iw->pub); + + WL_SOFTAP(("%s: Exited\n", __FUNCTION__)); + return ret; +} +#endif + + +#ifdef SOFTAP + +#define MAC_FILT_MAX 8 +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; + int mac_cnt = 0; + int mac_mode = 0; + struct ether_addr *p_ea; + struct mac_list_set mflist_set; + + WL_SOFTAP((">>> 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(&mflist_set, 0, sizeof(mflist_set)); + + + str_ptr = extra; + + + + if (get_parameter_from_string(&str_ptr, "MAC_MODE=", + PTYPE_INTDEC, &mac_mode, 4) != 0) { + WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n")); + goto exit_proc; + } + + p_ea = &mflist_set.mac_list.ea[0]; + + if (get_parameter_from_string(&str_ptr, "MAC_CNT=", + PTYPE_INTDEC, &mac_cnt, 4) != 0) { + WL_ERROR(("ERROR: 'MAC_CNT=' token 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_parameter_from_string(&str_ptr, "MAC=", + PTYPE_STR_HEX, &p_ea[i], 12) != 0) { + WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i)); + goto exit_proc; + } + + WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt)); + for (i = 0; i < mac_cnt; i++) { + WL_SOFTAP(("mac_filt[%d]:", i)); + dhd_print_buf(&p_ea[i], 6, 0); + } + + + mflist_set.mode = mac_mode; + mflist_set.mac_list.count = mac_cnt; + set_ap_mac_list(dev, &mflist_set); + + 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 + + +#ifdef SOFTAP + +static int iwpriv_set_ap_sta_disassoc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res = 0; + char sta_mac[6] = {0, 0, 0, 0, 0, 0}; + char cmd_buf[256]; + char *str_ptr = cmd_buf; + + WL_SOFTAP((">>%s called\n args: info->cmd:%x," + " info->flags:%x, u.data.p:%p, u.data.len:%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (wrqu->data.length != 0) { + + if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) { + return -EFAULT; + } + if (get_parameter_from_string(&str_ptr, + "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) { + res = wl_iw_softap_deassoc_stations(dev, sta_mac); + } else { + WL_ERROR(("ERROR: STA_MAC= token not found\n")); + } + } + + return res; +} +#endif #endif @@ -913,8 +2192,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 @@ -941,7 +2222,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; } @@ -974,13 +2255,19 @@ wl_iw_set_freq( int error, chan; uint sf = 0; - WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); + WL_TRACE(("%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) { chan = fwrq->m; } - else { @@ -992,16 +2279,20 @@ wl_iw_set_freq( while (fwrq->e++ < 6) fwrq->m /= 10; } - - if (fwrq->m > 4000 && fwrq->m < 5000) - sf = WF_CHAN_FACTOR_4_G; + + if (fwrq->m > 4000 && fwrq->m < 5000) + sf = WF_CHAN_FACTOR_4_G; chan = wf_mhz2channel(fwrq->m, sf); } + chan = htod32(chan); + if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) return error; + g_wl_iw_params.target_channel = chan; + return -EINPROGRESS; } @@ -1096,17 +2387,33 @@ wl_iw_get_range( ) { struct iw_range *range = (struct iw_range *) extra; - int channels[MAXCHANNEL+1]; - wl_uint32_list_t *list = (wl_uint32_list_t *) channels; + wl_uint32_list_t *list; wl_rateset_t rateset; - int error, i; + int8 *channels; + int error, i, k; uint sf, ch; + int phytype; + int bw_cap = 0, sgi_tx = 0, nmode = 0; + channel_info_t ci; + uint8 nrate_list2copy = 0; + uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, + {14, 29, 43, 58, 87, 116, 130, 144}, + {27, 54, 81, 108, 162, 216, 243, 270}, + {30, 60, 90, 120, 180, 240, 270, 300}}; + WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); if (!extra) return -EINVAL; + channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL); + if (!channels) { + WL_ERROR(("Could not alloc channels\n")); + return -ENOMEM; + } + list = (wl_uint32_list_t *)channels; + dwrq->length = sizeof(struct iw_range); memset(range, 0, sizeof(range)); @@ -1115,8 +2422,10 @@ wl_iw_get_range( list->count = htod32(MAXCHANNEL); - if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) + if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) { + kfree(channels); return error; + } for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { range->freq[i].i = dtoh32(list->element[i]); @@ -1150,16 +2459,49 @@ wl_iw_get_range( #endif - if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) + if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) { + kfree(channels); return error; + } rateset.count = dtoh32(rateset.count); range->num_bitrates = rateset.count; for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) - range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; + range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000; + dev_wlc_intvar_get(dev, "nmode", &nmode); + dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)); + + if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) { + dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); + dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); + dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); + ci.hw_channel = dtoh32(ci.hw_channel); + + if (bw_cap == 0 || + (bw_cap == 2 && ci.hw_channel <= 14)) { + if (sgi_tx == 0) + nrate_list2copy = 0; + else + nrate_list2copy = 1; + } + if (bw_cap == 1 || + (bw_cap == 2 && ci.hw_channel >= 36)) { + if (sgi_tx == 0) + nrate_list2copy = 2; + else + nrate_list2copy = 3; + } + range->num_bitrates += 8; + for (k = 0; i < range->num_bitrates; k++, i++) { + + range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; + } + } - if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) + if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) { + kfree(channels); return error; + } i = dtoh32(i); if (i == WLC_PHY_TYPE_A) range->throughput = 24000000; @@ -1217,11 +2559,20 @@ wl_iw_get_range( range->enc_capa = IW_ENC_CAPA_WPA; range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; -#ifdef BCMWPA2 range->enc_capa |= IW_ENC_CAPA_WPA2; -#endif + + + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); + IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); #endif + kfree(channels); + return 0; } @@ -1250,7 +2601,7 @@ wl_iw_set_spy( char *extra ) { - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); + wl_iw_t *iw = NETDEV_PRIV(dev); struct sockaddr *addr = (struct sockaddr *) extra; int i; @@ -1275,7 +2626,7 @@ wl_iw_get_spy( char *extra ) { - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); + wl_iw_t *iw = NETDEV_PRIV(dev); struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; int i; @@ -1296,6 +2647,43 @@ wl_iw_get_spy( return 0; } + +static int +wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size) +{ + chanspec_t chanspec = 0; + + if (ch != 0) { + + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0]) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + + *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(chanspec_t); + + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + htodchanspec(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); + + WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", + __FUNCTION__, join_params->params.chanspec_list[0])); + } + return 1; +} + static int wl_iw_set_wap( struct net_device *dev, @@ -1306,6 +2694,7 @@ wl_iw_set_wap( { int error = -EINVAL; wl_join_params_t join_params; + int join_params_size; WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); @@ -1319,6 +2708,7 @@ wl_iw_set_wap( scb_val_t scbval; bzero(&scbval, sizeof(scb_val_t)); + (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); return 0; } @@ -1326,16 +2716,28 @@ wl_iw_set_wap( memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid); memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN); - if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params)))) { - WL_ERROR(("Invalid ioctl data.\n")); + + + WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel)); + wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) { + WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error)); return error; } + if (g_ssid.SSID_len) { + WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, + g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), + g_wl_iw_params.target_channel)); + } + memset(&g_ssid, 0, sizeof(g_ssid)); return 0; @@ -1402,6 +2804,7 @@ wl_iw_mlme( } #endif +#ifndef WL_IW_USE_ISCAN static int wl_iw_get_aplist( struct net_device *dev, @@ -1436,7 +2839,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; @@ -1474,6 +2882,7 @@ wl_iw_get_aplist( return 0; } +#endif #ifdef WL_IW_USE_ISCAN static int @@ -1498,15 +2907,20 @@ wl_iw_iscan_get_aplist( if (!extra) return -EINVAL; - if ((!iscan) || (iscan->sysioc_pid < 0)) { - return wl_iw_get_aplist(dev, info, dwrq, extra); + if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) { + WL_ERROR(("%s error\n", __FUNCTION__)); + return 0; } buf = iscan->list_hdr; 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++) { @@ -1553,13 +2967,18 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; - params->scan_type = -1; + params->scan_type = 0; params->nprobes = -1; params->active_time = -1; params->passive_time = -1; params->home_time = -1; params->channel_num = 0; +#if defined(CONFIG_FIRST_SCAN) + + if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) + params->passive_time = 30; +#endif params->nprobes = htod32(params->nprobes); params->active_time = htod32(params->active_time); params->passive_time = htod32(params->passive_time); @@ -1573,33 +2992,25 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) { - int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); - wl_iscan_params_t *params; int err = 0; - if (ssid && ssid->SSID_len) { - params_size += sizeof(wlc_ssid_t); - } - params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); - if (params == NULL) { - return -ENOMEM; + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(action); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes)); + WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); + WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); + WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); + WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); + WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); + + if ((dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, + iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { + WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); + err = -1; } - memset(params, 0, params_size); - ASSERT(params_size < WLC_IOCTL_SMLEN); - - err = wl_iw_iscan_prep(¶ms->params, ssid); - - if (!err) { - params->version = htod32(ISCAN_REQ_VERSION); - params->action = htod16(action); - params->scan_duration = htod16(0); - - (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, - iscan->ioctlbuf, WLC_IOCTL_SMLEN); - } - - kfree(params); return err; } @@ -1611,11 +3022,13 @@ wl_iw_timerfunc(ulong data) iscan->timer_on = 0; if (iscan->iscan_state != ISCAN_STATE_IDLE) { WL_TRACE(("timer trigger\n")); - up(&iscan->sysioc_sem); + up(&iscan->tsk_ctl.sema); } } } -static void wl_iw_set_event_mask(struct net_device *dev) + +static void +wl_iw_set_event_mask(struct net_device *dev) { char eventmask[WL_EVENTING_MASK_LEN]; char iovbuf[WL_EVENTING_MASK_LEN + 12]; @@ -1636,16 +3049,21 @@ wl_iw_iscan_get(iscan_info_t *iscan) wl_iscan_results_t list; wl_scan_results_t *results; uint32 status; + int res = 0; - + DHD_OS_MUTEX_LOCK(&wl_cache_lock); if (iscan->list_cur) { buf = iscan->list_cur; iscan->list_cur = buf->next; } 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__)); + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); + return WL_SCAN_RESULTS_NO_MEM; + } buf->next = NULL; if (!iscan->list_hdr) iscan->list_hdr = buf; @@ -1666,48 +3084,99 @@ wl_iw_iscan_get(iscan_info_t *iscan) memset(&list, 0, sizeof(list)); list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); - (void) dev_iw_iovar_getbuf( + res = dev_iw_iovar_getbuf( iscan->dev, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, buf->iscan_buf, WLC_IW_ISCAN_MAXLEN); - results->buflen = dtoh32(results->buflen); - results->version = dtoh32(results->version); - results->count = dtoh32(results->count); - WL_TRACE(("results->count = %d\n", results->count)); - - WL_TRACE(("results->buflen = %d\n", results->buflen)); - status = dtoh32(list_buf->status); + if (res == 0) { + results->buflen = dtoh32(results->buflen); + results->version = dtoh32(results->version); + results->count = dtoh32(results->count); + WL_TRACE(("results->count = %d\n", results->count)); + WL_TRACE(("results->buflen = %d\n", results->buflen)); + status = dtoh32(list_buf->status); + } else { + WL_ERROR(("%s returns error %d\n", __FUNCTION__, res)); + + status = WL_SCAN_RESULTS_NO_MEM; + } + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); return status; } -static void wl_iw_send_scan_complete(iscan_info_t *iscan) +static void +wl_iw_force_specific_scan(iscan_info_t *iscan) +{ + 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)); - wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, extra); - WL_TRACE(("Send Event SCAN complete\n")); -#endif + memset(&wrqu, 0, sizeof(wrqu)); + + + wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); +#if defined(CONFIG_FIRST_SCAN) + if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; +#endif + WL_TRACE(("Send Event ISCAN complete\n")); +#endif } + static int _iscan_sysioc_thread(void *data) { uint32 status; - iscan_info_t *iscan = (iscan_info_t *)data; + + tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data; + iscan_info_t *iscan = (iscan_info_t *) tsk_ctl->parent; + + + static bool iscan_pass_abort = FALSE; DAEMONIZE("iscan_sysioc"); status = WL_SCAN_RESULTS_PARTIAL; - while (down_interruptible(&iscan->sysioc_sem) == 0) { + + + complete(&tsk_ctl->completed); + + while (down_interruptible(&tsk_ctl->sema) == 0) { + + SMP_RD_BARRIER_DEPENDS(); + if (tsk_ctl->terminated) { + break; + } +#if defined(SOFTAP) + + if (ap_cfg_running) { + WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__)); + net_os_wake_unlock(iscan->dev); + 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)) @@ -1718,6 +3187,13 @@ _iscan_sysioc_thread(void *data) rtnl_unlock(); #endif + if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) { + WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status)); + wl_iw_send_scan_complete(iscan); + iscan_pass_abort = FALSE; + status = -1; + } + switch (status) { case WL_SCAN_RESULTS_PARTIAL: WL_TRACE(("iscanresults incomplete\n")); @@ -1747,34 +3223,62 @@ _iscan_sysioc_thread(void *data) case WL_SCAN_RESULTS_ABORTED: WL_TRACE(("iscanresults aborted\n")); iscan->iscan_state = ISCAN_STATE_IDLE; - wl_iw_send_scan_complete(iscan); + if (g_scan_specified_ssid == 0) + wl_iw_send_scan_complete(iscan); + else { + iscan_pass_abort = TRUE; + 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); + complete_and_exit(&tsk_ctl->completed, 0); } #endif +#if !defined(CSCAN) +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; } @@ -1787,6 +3291,7 @@ wl_iw_free_ss_cache(void) WL_TRACE(("%s called\n", __FUNCTION__)); + DHD_OS_MUTEX_LOCK(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; @@ -1797,14 +3302,9 @@ wl_iw_free_ss_cache(void) kfree(cur); } *spec_scan_head = NULL; + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); } -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 @@ -1814,35 +3314,34 @@ 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) { - del_timer(*timer); - kfree(*timer); - *timer = NULL; + if (*timer) { + if (kick_off) { +#ifdef CONFIG_PRESCANNED + (*timer)->expires = jiffies + 70000 * HZ / 1000; +#else + (*timer)->expires = jiffies + 30000 * HZ / 1000; +#endif + add_timer(*timer); + WL_TRACE(("%s : timer starts \n", __FUNCTION__)); + } else { + del_timer_sync(*timer); + WL_TRACE(("%s : timer stops \n", __FUNCTION__)); } - WL_TRACE(("%s : timer stops \n", __FUNCTION__)); } return 0; } -void +static 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); + } } @@ -1853,6 +3352,7 @@ wl_iw_reset_ss_cache(void) wl_iw_ss_cache_t *node, *prev, *cur; wl_iw_ss_cache_t **spec_scan_head; + DHD_OS_MUTEX_LOCK(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -1879,7 +3379,7 @@ wl_iw_reset_ss_cache(void) prev = node; node = node->next; } - + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); } @@ -1892,13 +3392,14 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) wl_bss_info_t *bi = NULL; int i; - spec_scan_head = &g_ss_cache_ctrl.m_cache_head; if (!ss_list->count) { return 0; } - + DHD_OS_MUTEX_LOCK(&wl_cache_lock); + spec_scan_head = &g_ss_cache_ctrl.m_cache_head; + for (i = 0; i < ss_list->count; i++) { node = *spec_scan_head; @@ -1906,7 +3407,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)) { @@ -1921,17 +3422,15 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) if (node) { continue; } - leaf = kmalloc(WLC_IW_SS_CACHE_MAXLEN, GFP_KERNEL); + + leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); if (!leaf) { + WL_ERROR(("Memory alloc failure %d\n", + bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)); + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); return -ENOMEM; } - if (bi->length > WLC_IW_BSS_INFO_MAXLEN) { - WL_TRACE(("bss info length is too long : %d\n", bi->length)); - kfree(leaf); - continue; - } - memcpy(leaf->bss_info, bi, bi->length); leaf->next = NULL; leaf->dirty = 1; @@ -1945,8 +3444,8 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) prev->next = leaf; } } + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); return 0; - } @@ -1957,19 +3456,22 @@ __u16 *merged_len) wl_iw_ss_cache_t *node; wl_scan_results_t *list_merge; + DHD_OS_MUTEX_LOCK(&wl_cache_lock); 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)); + list_merge = (wl_scan_results_t *)&node->buflen; + 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; } + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); return 0; } @@ -1981,6 +3483,7 @@ wl_iw_delete_bss_from_ss_cache(void *addr) wl_iw_ss_cache_t *node, *prev; wl_iw_ss_cache_t **spec_scan_head; + DHD_OS_MUTEX_LOCK(&wl_cache_lock); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -2003,11 +3506,11 @@ wl_iw_delete_bss_from_ss_cache(void *addr) } memset(addr, 0, ETHER_ADDR_LEN); + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); return 0; - } - +#endif static int wl_iw_set_scan( @@ -2017,38 +3520,130 @@ wl_iw_set_scan( char *extra ) { - wlc_ssid_t ssid; + int error; + WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name)); + +#ifdef OEM_CHROMIUMOS + g_set_essid_before_scan = FALSE; +#endif - WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); +#if defined(CSCAN) + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); + return -EINVAL; +#endif + +#if defined(SOFTAP) + + if (ap_cfg_running) { + WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + return 0; + } +#endif if (g_onoff == G_WLAN_SET_OFF) return 0; - memset(&ssid, 0, sizeof(ssid)); - g_scan_specified_ssid = 0; + memset(&g_specific_ssid, 0, sizeof(g_specific_ssid)); +#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; - 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; - WL_TRACE(("Specific scan ssid=%s len=%d\n", ssid.SSID, ssid.SSID_len)); +#if defined(CONFIG_FIRST_SCAN) + 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; + } +#endif + 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, &ssid, sizeof(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 defined(CONFIG_FIRST_SCAN) + + 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; + } +#endif + +#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")); + + memset(&ssid, 0, sizeof(ssid)); + + iscan->list_cur = iscan->list_hdr; + iscan->iscan_state = ISCAN_STATE_SCANING; + + memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size); + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid); + 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, @@ -2059,53 +3654,101 @@ wl_iw_iscan_set_scan( { wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; + int ret = 0; + + WL_TRACE_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); - WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); +#if defined(CSCAN) + WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__)); + return -EINVAL; +#endif + + net_os_wake_lock(dev); - if (g_onoff == G_WLAN_SET_OFF) - return 0; +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + goto set_scan_end; + } +#endif + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + goto set_scan_end; + } +#ifdef PNO_SUPPORT - if ((!iscan) || (iscan->sysioc_pid < 0)) { - return wl_iw_set_scan(dev, info, wrqu, extra); + if (dhd_dev_get_pno_status(dev)) { + WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); } - if (iscan->iscan_state == ISCAN_STATE_SCANING) { - return 0; +#endif + + + if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) { + WL_ERROR(("%s error \n", __FUNCTION__)); + goto set_scan_end; + } + + if (g_scan_specified_ssid) { + WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", + __FUNCTION__)); + ret = EBUSY; + goto set_scan_end; } 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; + 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)); - return wl_iw_set_scan(dev, info, wrqu, extra); + dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as)); + wl_iw_set_event_mask(dev); + ret = wl_iw_set_scan(dev, info, wrqu, extra); + goto set_scan_end; + } + else { + g_scan_specified_ssid = 0; + + if (iscan->iscan_state == ISCAN_STATE_SCANING) { + WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__)); + goto set_scan_end; + } } } #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); - del_timer(&iscan->timer); - iscan->timer.expires = jiffies + iscan->timer_ms*HZ/1000; - add_timer(&iscan->timer); - iscan->timer_on = 1; +#if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN) + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { - return 0; + WL_ERROR(("%s Clean up First scan flag which is %d\n", + __FUNCTION__, g_first_broadcast_scan)); + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; + } + else { + WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", + __FUNCTION__, g_first_counter_scans)); + ret = -EBUSY; + goto set_scan_end; + } + } +#endif + + wl_iw_iscan_set_scan_broadcast_prep(dev, 0); + +set_scan_end: + net_os_wake_unlock(dev); + return ret; } #endif @@ -2155,34 +3798,6 @@ ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) } #endif -#ifdef BCMWAPI_WPI -static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, - size_t len, int uppercase) -{ - size_t i; - char *pos = buf, *end = buf + buf_size; - int ret; - if (buf_size == 0) - return 0; - for (i = 0; i < len; i++) { - ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", - data[i]); - if (ret < 0 || ret >= end - pos) { - end[-1] = '\0'; - return pos - buf; - } - pos += ret; - } - end[-1] = '\0'; - return pos - buf; -} - - -int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) -{ - return _wpa_snprintf_hex(buf, buf_size, data, len, 0); -} -#endif static int wl_iw_handle_scanresults_ies(char **event_p, char *end, @@ -2191,10 +3806,6 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, #if WIRELESS_EXT > 17 struct iw_event iwe; char *event; -#ifdef BCMWAPI_WPI - char *buf; - int custom_event_len; -#endif event = *event_p; if (bi->ie_length) { @@ -2203,14 +3814,12 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); int ptr_len = bi->ie_length; -#ifdef BCMWPA2 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); } ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -#endif while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { @@ -2233,37 +3842,6 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, } } -#ifdef BCMWAPI_WPI - ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); - ptr_len = bi->ie_length; - - while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) { - WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__)); -#ifdef WAPI_IE_USE_GENIE - iwe.cmd = IWEVGENIE; - iwe.u.data.length = ie->len + 2; - event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -#else - iwe.cmd = IWEVCUSTOM; - custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2); - iwe.u.data.length = custom_event_len; - - buf = kmalloc(custom_event_len+1, GFP_KERNEL); - if (buf == NULL) - { - WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len)); - break; - } - - memcpy(buf, "wapi_ie=", 8); - wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1); - wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1); - wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len); - event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf); -#endif - break; - } -#endif *event_p = event; } #endif @@ -2271,12 +3849,13 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end, return 0; } +#ifndef CSCAN static uint wl_iw_get_scan_prep( wl_scan_results_t *list, struct iw_request_info *info, char *extra, - __u16 max_size) + short max_size) { int i, j; struct iw_event iwe; @@ -2284,13 +3863,19 @@ wl_iw_get_scan_prep( char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value; int ret = 0; - ASSERT(list); + if (!list) { + WL_ERROR(("%s: Null list pointer", __FUNCTION__)); + return ret; + } - for (i = 0; i < list->count && i < IW_MAX_AP; i++) - { - ASSERT(list->version == WL_BSS_INFO_VERSION); + for (i = 0; i < list->count && i < IW_MAX_AP; i++) { + 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; @@ -2346,23 +3931,27 @@ wl_iw_get_scan_prep( if (bi->rateset.count) { - 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; - value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, - IW_EV_PARAM_LEN); + 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; + value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, + IW_EV_PARAM_LEN); + } + event = value; } - event = value; } - } + } if ((ret = (event - extra)) < 0) { WL_ERROR(("==> Wrong size\n")); ret = 0; } + WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra))); return (uint)ret; } @@ -2382,11 +3971,16 @@ wl_iw_get_scan( uint buflen_from_user = dwrq->length; uint len = G_SCAN_RESULTS; __u16 len_ret = 0; +#if !defined(CSCAN) __u16 merged_len = 0; +#endif #if defined(WL_IW_USE_ISCAN) iscan_info_t *iscan = g_iscan; iscan_buf_t * p_buf; -#endif +#if !defined(CSCAN) + uint32 counter = 0; +#endif +#endif WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user)); @@ -2402,6 +3996,7 @@ wl_iw_get_scan( if (ci.scan_channel) return -EAGAIN; +#if !defined(CSCAN) if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); g_ss_cache_ctrl.m_timer_expired ^= 1; @@ -2409,7 +4004,6 @@ wl_iw_get_scan( if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) { g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; - wl_iw_reset_ss_cache(); } @@ -2420,6 +4014,8 @@ wl_iw_get_scan( else { g_ss_cache_ctrl.m_cons_br_scan_cnt++; } +#endif + if (g_scan_specified_ssid) { @@ -2427,6 +4023,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; } } @@ -2434,49 +4031,105 @@ 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_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error)); dwrq->length = len; - if (g_scan_specified_ssid) + if (g_scan_specified_ssid) { + g_scan_specified_ssid = 0; kfree(list); + } return 0; } list->buflen = dtoh32(list->buflen); list->version = dtoh32(list->version); list->count = dtoh32(list->count); + + if (list->version != WL_BSS_INFO_VERSION) { + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __FUNCTION__, list->version)); + if (g_scan_specified_ssid) { + g_scan_specified_ssid = 0; + kfree(list); + } + return -EINVAL; + } + +#if !defined(CSCAN) if (g_scan_specified_ssid) { wl_iw_add_bss_to_ss_cache(list); kfree(list); } +#endif +#if !defined(CSCAN) + DHD_OS_MUTEX_LOCK(&wl_cache_lock); #if defined(WL_IW_USE_ISCAN) + if (g_scan_specified_ssid) + WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count)); 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); 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 + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); if (g_ss_cache_ctrl.m_link_down) { - wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); } - wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len); len_ret += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); +#else + + + if (g_scan_specified_ssid) { + WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count)); + len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); + kfree(list); + +#if defined(WL_IW_USE_ISCAN) + 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)); + if (list_merge->count > 0) + len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, + extra+len_ret, buflen_from_user -len_ret); + p_buf = p_buf->next; + } +#else + list_merge = (wl_scan_results_t *) g_scan; + WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, 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); +#endif + } + else { + list = (wl_scan_results_t *) g_scan; + len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); + } +#endif +#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; @@ -2487,7 +4140,7 @@ wl_iw_get_scan( WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count)); return 0; } - +#endif #if defined(WL_IW_USE_ISCAN) static int @@ -2507,23 +4160,42 @@ wl_iw_iscan_get_scan( iscan_info_t *iscan = g_iscan; iscan_buf_t * p_buf; uint32 counter = 0; + uint8 channel; +#if !defined(CSCAN) __u16 merged_len = 0; uint buflen_from_user = dwrq->length; +#endif 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 defined(CONFIG_FIRST_SCAN) + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { + WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", + dev->name, __FUNCTION__)); + return -EAGAIN; + } +#endif - if ((!iscan) || (iscan->sysioc_pid < 0)) { - return wl_iw_get_scan(dev, info, dwrq, extra); + if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) { + WL_ERROR(("%ssysioc_pid\n", __FUNCTION__)); + return EAGAIN; } +#if !defined(CSCAN) if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); g_ss_cache_ctrl.m_timer_expired ^= 1; @@ -2533,128 +4205,217 @@ wl_iw_iscan_get_scan( } else { if (g_ss_cache_ctrl.m_link_down) { - wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); } if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) { g_ss_cache_ctrl.m_cons_br_scan_cnt = 0; - wl_iw_reset_ss_cache(); } g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid; g_ss_cache_ctrl.m_cons_br_scan_cnt++; } +#endif WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name)); apcnt = 0; p_buf = iscan->list_hdr; while (p_buf != iscan->list_cur) { - list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; + 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)); - } - - bi = NULL; - for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { - bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; - ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + - WLC_IW_ISCAN_MAXLEN)); + if (list->version != WL_BSS_INFO_VERSION) { + WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __FUNCTION__, list->version)); + return -EINVAL; + } - - if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + - IW_EV_QUAL_LEN >= end) - return -E2BIG; - - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); - event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); + bi = NULL; + for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { + bi = (bi ? + (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : + list->bss_info); + ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + + WLC_IW_ISCAN_MAXLEN)); - - iwe.u.data.length = dtoh32(bi->SSID_len); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); + + if (event + ETHER_ADDR_LEN + bi->SSID_len + + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end) + return -E2BIG; + + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); - - if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { - iwe.cmd = SIOCGIWMODE; - if (dtoh16(bi->capability) & DOT11_CAP_ESS) - iwe.u.mode = IW_MODE_INFRA; - else - iwe.u.mode = IW_MODE_ADHOC; - event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); - } + + iwe.u.data.length = dtoh32(bi->SSID_len); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), - CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); - iwe.u.freq.e = 6; - event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); + + if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { + iwe.cmd = SIOCGIWMODE; + if (dtoh16(bi->capability) & DOT11_CAP_ESS) + iwe.u.mode = IW_MODE_INFRA; + else + iwe.u.mode = IW_MODE_ADHOC; + event = IWE_STREAM_ADD_EVENT(info, event, end, + &iwe, IW_EV_UINT_LEN); + } - - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); - iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); - iwe.u.qual.noise = 0x100 + bi->phy_noise; - event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); + + iwe.cmd = SIOCGIWFREQ; + channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch; + iwe.u.freq.m = wf_channel2mhz(channel, + channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); + iwe.u.freq.e = 6; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); - - wl_iw_handle_scanresults_ies(&event, end, info, bi); + + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); + iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); + iwe.u.qual.noise = 0x100 + bi->phy_noise; + event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); - - iwe.cmd = SIOCGIWENCODE; - if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); + + wl_iw_handle_scanresults_ies(&event, end, info, bi); - - if (bi->rateset.count) { - if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) - return -E2BIG; + + iwe.cmd = SIOCGIWENCODE; + if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); - 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; - value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, - IW_EV_PARAM_LEN); + if (bi->rateset.count) { + if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) + return -E2BIG; + + 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; + value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, + IW_EV_PARAM_LEN); + } + event = value; } - event = value; } - } - p_buf = p_buf->next; + p_buf = p_buf->next; } - dwrq->length = event - extra; dwrq->flags = 0; +#if !defined(CSCAN) wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len); dwrq->length += merged_len; wl_iw_run_ss_cache_timer(0); wl_iw_run_ss_cache_timer(1); +#endif + +#if defined(CONFIG_FIRST_SCAN) + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; +#endif WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); + + if (!dwrq->length) + return -EAGAIN; + return 0; } #endif +#define WL_JOIN_PARAMS_MAX 1600 +#ifdef CONFIG_PRESCANNED +static int +check_prescan(wl_join_params_t *join_params, int *join_params_size) +{ + int cnt = 0; + int indx = 0; + wl_iw_ss_cache_t *node = NULL; + wl_bss_info_t *bi = NULL; + iscan_info_t *iscan = g_iscan; + iscan_buf_t * buf; + wl_scan_results_t *list; + char *destbuf; + + buf = iscan->list_hdr; + + while (buf) { + list = &((wl_iscan_results_t*)buf->iscan_buf)->results; + bi = NULL; + for (indx = 0; indx < list->count; indx++) { + bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) + : list->bss_info; + if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) + continue; + if ((dtoh32(bi->SSID_len) != join_params->ssid.SSID_len) || + memcmp(bi->SSID, join_params->ssid.SSID, + join_params->ssid.SSID_len)) + continue; + memcpy(&join_params->params.chanspec_list[cnt], + &bi->chanspec, sizeof(chanspec_t)); + WL_ERROR(("iscan : chanspec :%d, count %d \n", bi->chanspec, cnt)); + cnt++; + } + buf = buf->next; + } + + if (!cnt) { + MUTEX_LOCK_WL_SCAN_SET(); + node = g_ss_cache_ctrl.m_cache_head; + for (; node; ) { + if (!memcmp(&node->bss_info->SSID, join_params->ssid.SSID, + join_params->ssid.SSID_len)) { + memcpy(&join_params->params.chanspec_list[cnt], + &node->bss_info->chanspec, sizeof(chanspec_t)); + WL_ERROR(("cache_scan : chanspec :%d, count %d \n", + (int)node->bss_info->chanspec, cnt)); + cnt++; + } + node = node->next; + } + MUTEX_UNLOCK_WL_SCAN_SET(); + } + + if (!cnt) { + return 0; + } + + destbuf = (char *)&join_params->params.chanspec_list[cnt]; + *join_params_size = destbuf - (char*)join_params; + join_params->ssid.SSID_len = htod32(g_ssid.SSID_len); + memcpy(&(join_params->params.bssid), ðer_bcast, ETHER_ADDR_LEN); + join_params->params.chanspec_num = htod32(cnt); + + if ((*join_params_size) > WL_JOIN_PARAMS_MAX) { + WL_ERROR(("can't fit bssids for all %d APs found\n", cnt)); + kfree(join_params); + return 0; + } + + WL_ERROR(("Passing %d channel/bssid pairs.\n", cnt)); + return cnt; +} +#endif + static int wl_iw_set_essid( struct net_device *dev, @@ -2664,9 +4425,24 @@ wl_iw_set_essid( ) { int error; + wl_join_params_t *join_params; + int join_params_size; WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); + RETURN_IF_EXTRA_NULL(extra); + +#ifdef OEM_CHROMIUMOS + if (g_set_essid_before_scan) + return -EAGAIN; +#endif + if (!(join_params = kmalloc(WL_JOIN_PARAMS_MAX, GFP_KERNEL))) { + WL_ERROR(("allocation failed for join_params size is %d\n", WL_JOIN_PARAMS_MAX)); + return -ENOMEM; + } + + memset(join_params, 0, WL_JOIN_PARAMS_MAX); + memset(&g_ssid, 0, sizeof(g_ssid)); @@ -2677,14 +4453,52 @@ wl_iw_set_essid( g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1); #endif memcpy(g_ssid.SSID, extra, g_ssid.SSID_len); + +#ifdef CONFIG_PRESCANNED + memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); + join_params->ssid.SSID_len = g_ssid.SSID_len; + + if (check_prescan(join_params, &join_params_size)) { + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, + join_params, join_params_size))) { + WL_ERROR(("Invalid ioctl data=%d\n", error)); + kfree(join_params); + return error; + } + kfree(join_params); + return 0; + } else { + WL_ERROR(("No matched found\n Trying to join to specific channel\n")); + } +#endif } else { g_ssid.SSID_len = 0; } g_ssid.SSID_len = htod32(g_ssid.SSID_len); - if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &g_ssid, sizeof(g_ssid)))) + + + memset(join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params->ssid); + + memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); + join_params->ssid.SSID_len = htod32(g_ssid.SSID_len); + memcpy(&(join_params->params.bssid), ðer_bcast, ETHER_ADDR_LEN); + + + + wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, join_params, &join_params_size); + + if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, join_params, join_params_size))) { + WL_ERROR(("Invalid ioctl data=%d\n", error)); return error; + } + if (g_ssid.SSID_len) { + WL_ERROR(("%s: join SSID=%s ch=%d\n", __FUNCTION__, + g_ssid.SSID, g_wl_iw_params.target_channel)); + } + kfree(join_params); return 0; } @@ -2729,7 +4543,7 @@ wl_iw_set_nick( char *extra ) { - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); + wl_iw_t *iw = NETDEV_PRIV(dev); WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); @@ -2754,7 +4568,7 @@ wl_iw_get_nick( char *extra ) { - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); + wl_iw_t *iw = NETDEV_PRIV(dev); WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); @@ -2767,7 +4581,8 @@ wl_iw_get_nick( return 0; } -static int wl_iw_set_rate( +static int +wl_iw_set_rate( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, @@ -2827,7 +4642,8 @@ static int wl_iw_set_rate( return 0; } -static int wl_iw_get_rate( +static int +wl_iw_get_rate( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, @@ -2842,7 +4658,7 @@ static int wl_iw_get_rate( if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) return error; rate = dtoh32(rate); - vwrq->value = (rate & 0x7f) * 500000; + vwrq->value = rate * 500000; return 0; } @@ -3027,20 +4843,31 @@ wl_iw_set_retry( if (vwrq->flags & IW_RETRY_LIMIT) { + - if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { +#if WIRELESS_EXT > 20 + if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || + !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { +#else + if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { +#endif lrl = htod32(vwrq->value); if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) return error; } + +#if WIRELESS_EXT > 20 + if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || + !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { +#else if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { +#endif srl = htod32(vwrq->value); if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) return error; } } - return 0; } @@ -3096,7 +4923,13 @@ wl_iw_set_encode( wl_wsec_key_t key; int error, val, wsec; - WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name)); + WL_TRACE(("%s: SIOCSIWENCODE index %d, len %d, flags %04x (%s%s%s%s%s)\n", + dev->name, dwrq->flags & IW_ENCODE_INDEX, dwrq->length, dwrq->flags, + dwrq->flags & IW_ENCODE_NOKEY ? "NOKEY" : "", + dwrq->flags & IW_ENCODE_DISABLED ? " DISABLED" : "", + dwrq->flags & IW_ENCODE_RESTRICTED ? " RESTRICTED" : "", + dwrq->flags & IW_ENCODE_OPEN ? " OPEN" : "", + dwrq->flags & IW_ENCODE_TEMP ? " TEMP" : "")); memset(&key, 0, sizeof(key)); @@ -3295,21 +5128,21 @@ wl_iw_set_wpaie( char *extra ) { -#if defined(BCMWAPI_WPI) - uchar buf[WLC_IOCTL_SMLEN] = {0}; - uchar *p = buf; - int wapi_ie_size; WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name)); - if (extra[0] == DOT11_MNG_WAPI_ID) + RETURN_IF_EXTRA_NULL(extra); + +#ifdef DHD_DEBUG { - wapi_ie_size = iwp->length; - memcpy(p, extra, iwp->length); - dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size); + int i; + + for (i = 0; i < iwp->length; i++) + WL_TRACE(("%02X ", extra[i])); + WL_TRACE(("\n")); } - else #endif + dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); return 0; @@ -3343,6 +5176,8 @@ wl_iw_set_encodeext( WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); + RETURN_IF_EXTRA_NULL(extra); + memset(&key, 0, sizeof(key)); iwe = (struct iw_encode_ext *)extra; @@ -3376,7 +5211,7 @@ wl_iw_set_encodeext( else { swap_key_from_BE(&key); - (void) dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); } } else { @@ -3424,14 +5259,6 @@ wl_iw_set_encodeext( case IW_ENCODE_ALG_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; break; -#ifdef BCMWAPI_WPI - case IW_ENCODE_ALG_SM4: - key.algo = CRYPTO_ALGO_SMS4; - if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - key.flags &= ~WL_PRIMARY_KEY; - } - break; -#endif default: break; } @@ -3446,6 +5273,123 @@ wl_iw_set_encodeext( return 0; } +#if WIRELESS_EXT > 17 +struct { + pmkid_list_t pmkids; + pmkid_t foo[MAXPMKID-1]; +} pmkid_list; + +static int +wl_iw_set_pmksa( + struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra +) +{ + struct iw_pmksa *iwpmksa; + uint i; + int ret = 0; + char eabuf[ETHER_ADDR_STR_LEN]; + + WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name)); + + RETURN_IF_EXTRA_NULL(extra); + + iwpmksa = (struct iw_pmksa *)extra; + bzero((char *)eabuf, ETHER_ADDR_STR_LEN); + + if (iwpmksa->cmd == IW_PMKSA_FLUSH) { + WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); + bzero((char *)&pmkid_list, sizeof(pmkid_list)); + } + + else if (iwpmksa->cmd == IW_PMKSA_REMOVE) { + { + pmkid_list_t pmkid, *pmkidptr; + uint j; + pmkidptr = &pmkid; + + bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, + ETHER_ADDR_LEN); + bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); + + WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", + bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, + eabuf))); + for (j = 0; j < WPA2_PMKID_LEN; j++) + WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j])); + WL_WSEC(("\n")); + } + + for (i = 0; i < pmkid_list.pmkids.npmkid; i++) + if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + + if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) { + bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t)); + for (; i < (pmkid_list.pmkids.npmkid - 1); i++) { + bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID, + &pmkid_list.pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN); + bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID, + &pmkid_list.pmkids.pmkid[i].PMKID, + WPA2_PMKID_LEN); + } + pmkid_list.pmkids.npmkid--; + } + else + ret = -EINVAL; + } + + else if (iwpmksa->cmd == IW_PMKSA_ADD) { + for (i = 0; i < pmkid_list.pmkids.npmkid; i++) + if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN)) + break; + if (i < MAXPMKID) { + bcopy(&iwpmksa->bssid.sa_data[0], + &pmkid_list.pmkids.pmkid[i].BSSID, + ETHER_ADDR_LEN); + bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID, + WPA2_PMKID_LEN); + if (i == pmkid_list.pmkids.npmkid) + pmkid_list.pmkids.npmkid++; + } + else + ret = -EINVAL; + + { + uint j; + uint k; + k = pmkid_list.pmkids.npmkid; + 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_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j])); + WL_WSEC(("\n")); + } + } + WL_WSEC(("PRINTING pmkid LIST - No of elements %d", pmkid_list.pmkids.npmkid)); + for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { + uint j; + WL_WSEC(("\nPMKID[%d]: %s = ", i, + bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID, + eabuf))); + for (j = 0; j < WPA2_PMKID_LEN; j++) + WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j])); + } + WL_WSEC(("\n")); + + if (!ret) + ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, + sizeof(pmkid_list)); + return ret; +} +#endif + static int wl_iw_get_encodeext( struct net_device *dev, @@ -3458,6 +5402,40 @@ wl_iw_get_encodeext( return 0; } + +static uint32 +wl_iw_create_wpaauth_wsec(struct net_device *dev) +{ + wl_iw_t *iw = NETDEV_PRIV(dev); + uint32 wsec; + + + if (iw->pcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + wsec = WEP_ENABLED; + else if (iw->pcipher & IW_AUTH_CIPHER_TKIP) + wsec = TKIP_ENABLED; + else if (iw->pcipher & IW_AUTH_CIPHER_CCMP) + wsec = AES_ENABLED; + else + wsec = 0; + + + if (iw->gcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) + wsec |= WEP_ENABLED; + else if (iw->gcipher & IW_AUTH_CIPHER_TKIP) + wsec |= TKIP_ENABLED; + else if (iw->gcipher & IW_AUTH_CIPHER_CCMP) + wsec |= AES_ENABLED; + + + if (wsec == 0 && iw->privacy_invoked) + wsec = WEP_ENABLED; + + WL_INFORM(("%s: returning wsec of %d\n", __FUNCTION__, wsec)); + + return wsec; +} + static int wl_iw_set_wpaauth( struct net_device *dev, @@ -3470,90 +5448,78 @@ wl_iw_set_wpaauth( int paramid; int paramval; int val = 0; - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); - - WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); + wl_iw_t *iw = NETDEV_PRIV(dev); paramid = vwrq->flags & IW_AUTH_INDEX; paramval = vwrq->value; - WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", - dev->name, paramid, paramval)); + WL_TRACE(("%s: SIOCSIWAUTH, %s(%d), paramval = 0x%0x\n", + dev->name, + paramid == IW_AUTH_WPA_VERSION ? "IW_AUTH_WPA_VERSION" : + paramid == IW_AUTH_CIPHER_PAIRWISE ? "IW_AUTH_CIPHER_PAIRWISE" : + paramid == IW_AUTH_CIPHER_GROUP ? "IW_AUTH_CIPHER_GROUP" : + paramid == IW_AUTH_KEY_MGMT ? "IW_AUTH_KEY_MGMT" : + paramid == IW_AUTH_TKIP_COUNTERMEASURES ? "IW_AUTH_TKIP_COUNTERMEASURES" : + paramid == IW_AUTH_DROP_UNENCRYPTED ? "IW_AUTH_DROP_UNENCRYPTED" : + paramid == IW_AUTH_80211_AUTH_ALG ? "IW_AUTH_80211_AUTH_ALG" : + paramid == IW_AUTH_WPA_ENABLED ? "IW_AUTH_WPA_ENABLED" : + paramid == IW_AUTH_RX_UNENCRYPTED_EAPOL ? "IW_AUTH_RX_UNENCRYPTED_EAPOL" : + paramid == IW_AUTH_ROAMING_CONTROL ? "IW_AUTH_ROAMING_CONTROL" : + paramid == IW_AUTH_PRIVACY_INVOKED ? "IW_AUTH_PRIVACY_INVOKED" : + "UNKNOWN", + paramid, paramval)); + +#if defined(SOFTAP) + if (ap_cfg_running) { + WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__)); + return 0; + } +#endif switch (paramid) { case IW_AUTH_WPA_VERSION: - if (paramval & IW_AUTH_WPA_VERSION_DISABLED) - val = WPA_AUTH_DISABLED; - else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) - val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; -#ifdef BCMWPA2 - else if (paramval & IW_AUTH_WPA_VERSION_WPA2) - val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; -#endif -#ifdef BCMWAPI_WPI - else if (paramval & IW_AUTH_WAPI_VERSION_1) - val = WPA_AUTH_WAPI; -#endif - WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); - if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) - return error; + iw->wpaversion = paramval; break; - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - - - if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - val = WEP_ENABLED; - if (paramval & IW_AUTH_CIPHER_TKIP) - val = TKIP_ENABLED; - if (paramval & IW_AUTH_CIPHER_CCMP) - val = AES_ENABLED; -#ifdef BCMWAPI_WPI - if (paramval & IW_AUTH_CIPHER_SMS4) - val = SMS4_ENABLED; -#endif - - if (paramid == IW_AUTH_CIPHER_PAIRWISE) { - iw->pwsec = val; - val |= iw->gwsec; - } - else { - iw->gwsec = val; - val |= iw->pwsec; - } + case IW_AUTH_CIPHER_PAIRWISE: + iw->pcipher = paramval; + val = wl_iw_create_wpaauth_wsec(dev); if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; - break; - case IW_AUTH_KEY_MGMT: - if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + case IW_AUTH_CIPHER_GROUP: + iw->gcipher = paramval; + val = wl_iw_create_wpaauth_wsec(dev); + if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; + break; - if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { - if (paramval & IW_AUTH_KEY_MGMT_PSK) + case IW_AUTH_KEY_MGMT: + if (paramval & IW_AUTH_KEY_MGMT_PSK) { + if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA) val = WPA_AUTH_PSK; - else - val = WPA_AUTH_UNSPECIFIED; - } -#ifdef BCMWPA2 - else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { - if (paramval & IW_AUTH_KEY_MGMT_PSK) + else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2) val = WPA2_AUTH_PSK; - else + else + val = WPA_AUTH_DISABLED; + } else if (paramval & IW_AUTH_KEY_MGMT_802_1X) { + if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA) + val = WPA_AUTH_UNSPECIFIED; + else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2) val = WPA2_AUTH_UNSPECIFIED; + else + val = WPA_AUTH_DISABLED; } -#endif -#ifdef BCMWAPI_WPI - if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT)) - val = WPA_AUTH_WAPI; -#endif + else + val = WPA_AUTH_DISABLED; + WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) return error; break; + case IW_AUTH_TKIP_COUNTERMEASURES: dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); break; @@ -3575,17 +5541,15 @@ wl_iw_set_wpaauth( case IW_AUTH_WPA_ENABLED: if (paramval == 0) { - iw->pwsec = 0; - iw->gwsec = 0; - if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) + iw->privacy_invoked = 0; + iw->pcipher = 0; + iw->gcipher = 0; + val = wl_iw_create_wpaauth_wsec(dev); + if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; - if (val & (TKIP_ENABLED | AES_ENABLED)) { - val &= ~(TKIP_ENABLED | AES_ENABLED); - dev_wlc_intvar_set(dev, "wsec", val); - } - val = 0; - WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); - dev_wlc_intvar_set(dev, "wpa_auth", 0); + WL_INFORM(("%s: %d: setting wpa_auth to %d, wsec to %d\n", + __FUNCTION__, __LINE__, paramval, val)); + dev_wlc_intvar_set(dev, "wpa_auth", paramval); return error; } @@ -3593,7 +5557,8 @@ wl_iw_set_wpaauth( break; case IW_AUTH_DROP_UNENCRYPTED: - dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); + if ((error = dev_wlc_intvar_set(dev, "wsec_restrict", paramval))) + return error; break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: @@ -3605,40 +5570,21 @@ wl_iw_set_wpaauth( WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); break; + case IW_AUTH_PRIVACY_INVOKED: - WL_INFORM(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__)); - break; -#endif -#ifdef BCMWAPI_WPI - case IW_AUTH_WAPI_ENABLED: - if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) + iw->privacy_invoked = paramval; + val = wl_iw_create_wpaauth_wsec(dev); + if ((error = dev_wlc_intvar_set(dev, "wsec", val))) return error; - if (paramval) { - val |= SMS4_ENABLED; - if ((error = dev_wlc_intvar_set(dev, "wsec", val))) { - WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n", - __FUNCTION__, val, error)); - return error; - } - if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) { - WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n", - __FUNCTION__, error)); - return error; - } - } - break; + #endif default: break; } return 0; } -#ifdef BCMWPA2 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) -#else -#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK)) -#endif static int wl_iw_get_wpaauth( @@ -3652,7 +5598,7 @@ wl_iw_get_wpaauth( int paramid; int paramval = 0; int val; - wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev); + wl_iw_t *iw = NETDEV_PRIV(dev); WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name)); @@ -3660,37 +5606,17 @@ wl_iw_get_wpaauth( switch (paramid) { case IW_AUTH_WPA_VERSION: - - if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) - return error; - if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) - paramval = IW_AUTH_WPA_VERSION_DISABLED; - else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) - paramval = IW_AUTH_WPA_VERSION_WPA; -#ifdef BCMWPA2 - else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) - paramval = IW_AUTH_WPA_VERSION_WPA2; -#endif + paramval = iw->wpaversion; break; + case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - if (paramid == IW_AUTH_CIPHER_PAIRWISE) - val = iw->pwsec; - else - val = iw->gwsec; + paramval = iw->pcipher; + break; - paramval = 0; - if (val) { - if (val & WEP_ENABLED) - paramval |= (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104); - if (val & TKIP_ENABLED) - paramval |= (IW_AUTH_CIPHER_TKIP); - if (val & AES_ENABLED) - paramval |= (IW_AUTH_CIPHER_CCMP); - } - else - paramval = IW_AUTH_CIPHER_NONE; + case IW_AUTH_CIPHER_GROUP: + paramval = iw->gcipher; break; + case IW_AUTH_KEY_MGMT: if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) @@ -3701,12 +5627,13 @@ wl_iw_get_wpaauth( paramval = IW_AUTH_KEY_MGMT_802_1X; break; + case IW_AUTH_TKIP_COUNTERMEASURES: dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); break; case IW_AUTH_DROP_UNENCRYPTED: - dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); + dev_wlc_intvar_get(dev, "wsec_restrict", ¶mval); break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: @@ -3736,8 +5663,9 @@ wl_iw_get_wpaauth( break; case IW_AUTH_PRIVACY_INVOKED: - WL_ERROR(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__)); + paramval = iw->privacy_invoked; break; + #endif } vwrq->value = paramval; @@ -3745,6 +5673,1639 @@ wl_iw_get_wpaauth( } #endif + +#ifdef SOFTAP + +static int ap_macmode = MACLIST_MODE_DISABLED; +static struct mflist ap_black_list; + +static int +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 +static 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 + + +static 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(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val)); + + return bss_set_res; +} + + + +#ifndef AP_ONLY +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; +} +#endif + + + + +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) + + +#if defined(CSCAN) + + + +static int +wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan) +{ + int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16); + int err = 0; + char *p; + int i; + iscan_info_t *iscan = g_iscan; + + WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan)); + + if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) { + WL_ERROR(("%s error exit\n", __FUNCTION__)); + err = -1; + goto exit; + } + +#ifdef PNO_SUPPORT + + if (dhd_dev_get_pno_status(dev)) { + WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__)); + } +#endif + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + + + if (nssid > 0) { + i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16); + i = ROUNDUP(i, sizeof(uint32)); + if (i + nssid * sizeof(wlc_ssid_t) > params_size) { + printf("additional ssids exceed params_size\n"); + err = -1; + goto exit; + } + + p = ((char*)&iscan->iscan_ex_params_p->params) + i; + memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t)); + p += nssid * sizeof(wlc_ssid_t); + } else { + p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16); + } + + + iscan->iscan_ex_params_p->params.channel_num = + htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | + (nchan & WL_SCAN_PARAMS_COUNT_MASK)); + + nssid = (uint) + ((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & + WL_SCAN_PARAMS_COUNT_MASK); + + + params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t)); + iscan->iscan_ex_param_size = params_size; + + iscan->list_cur = iscan->list_hdr; + iscan->iscan_state = ISCAN_STATE_SCANING; + wl_iw_set_event_mask(dev); + mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000); + + iscan->timer_on = 1; + +#ifdef SCAN_DUMP + { + int i; + WL_SCAN(("\n### List of SSIDs to scan ###\n")); + for (i = 0; i < nssid; i++) { + if (!ssids_local[i].SSID_len) + WL_SCAN(("%d: Broadcast scan\n", i)); + else + WL_SCAN(("%d: scan for %s size =%d\n", i, + ssids_local[i].SSID, ssids_local[i].SSID_len)); + } + WL_SCAN(("### List of channels to scan ###\n")); + for (i = 0; i < nchan; i++) + { + WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i])); + } + WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes)); + WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time)); + WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time)); + WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); + WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); + WL_SCAN(("\n###################\n")); + } +#endif + + if (params_size > WLC_IOCTL_MEDLEN) { + WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", + __FUNCTION__, params_size)); + err = -1; + } + + if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, + iscan->iscan_ex_param_size, + iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { + WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err)); + err = -1; + } + +exit: + return err; +} + + +static int +iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *ext) +{ + int res; + char *extra = NULL; + iscan_info_t *iscan = g_iscan; + wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; + int nssid = 0; + int nchan = 0; + char *str_ptr; + + WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return -ENODEV; + } + + if (wrqu->data.length == 0) { + WL_ERROR(("IWPRIV argument len = 0\n")); + return -EINVAL; + } + + if (!iscan->iscan_ex_params_p) { + return -EFAULT; + } + + if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) { + res = -EFAULT; + goto exit_proc; + } + + extra[wrqu->data.length] = 0; + WL_ERROR(("Got str param in iw_point:\n %s\n", extra)); + + str_ptr = extra; + + + if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) { + WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__)); + res = -EINVAL; + goto exit_proc; + } + + str_ptr += strlen(GET_SSID); + nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, + WL_SCAN_PARAMS_SSID_MAX); + if (nssid == -1) { + WL_ERROR(("%s wrong ssid list", __FUNCTION__)); + res = -EINVAL; + goto exit_proc; + } + + memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); + ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN); + + + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + + if ((nchan = wl_iw_parse_channel_list(&str_ptr, + &iscan->iscan_ex_params_p->params.channel_list[0], + WL_NUMCHANNELS)) == -1) { + WL_ERROR(("%s missing channel list\n", __FUNCTION__)); + res = -EINVAL; + goto exit_proc; + } + + + get_parameter_from_string(&str_ptr, + GET_NPROBE, PTYPE_INTDEC, + &iscan->iscan_ex_params_p->params.nprobes, 2); + + get_parameter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, + &iscan->iscan_ex_params_p->params.active_time, 4); + + get_parameter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, + &iscan->iscan_ex_params_p->params.passive_time, 4); + + get_parameter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, + &iscan->iscan_ex_params_p->params.home_time, 4); + + get_parameter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, + &iscan->iscan_ex_params_p->params.scan_type, 1); + + + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); + +exit_proc: + kfree(extra); + + return res; +} + + +static int +wl_iw_set_cscan( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int res = -1; + iscan_info_t *iscan = g_iscan; + wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX]; + int nssid = 0; + int nchan = 0; + cscan_tlv_t *cscan_tlv_temp; + char type; + char *str_ptr; + int tlv_size_left; +#ifdef TLV_DEBUG + int i; + char tlv_in_example[] = { + 'C', 'S', 'C', 'A', 'N', ' ', + 0x53, 0x01, 0x00, 0x00, + 'S', + 0x00, + 'S', + 0x04, + 'B', 'R', 'C', 'M', + 'C', + 0x06, + 'P', + 0x94, + 0x11, + 'T', + 0x01 + }; +#endif + + WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + net_os_wake_lock(dev); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + return -1; + } + + if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) { + WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, + wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))); + return -1; + } + +#ifdef TLV_DEBUG + memcpy(extra, tlv_in_example, sizeof(tlv_in_example)); + wrqu->data.length = sizeof(tlv_in_example); + for (i = 0; i < wrqu->data.length; i++) + printf("%02X ", extra[i]); + printf("\n"); +#endif + + str_ptr = extra; + str_ptr += strlen(CSCAN_COMMAND); + tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND); + + cscan_tlv_temp = (cscan_tlv_t *)str_ptr; + memset(ssids_local, 0, sizeof(ssids_local)); + + if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && + (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && + (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION)) + { + str_ptr += sizeof(cscan_tlv_t); + tlv_size_left -= sizeof(cscan_tlv_t); + + + if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, + WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) { + WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); + goto exit_proc; + } + else { + + memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size); + + + wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL); + iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION); + iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START); + iscan->iscan_ex_params_p->scan_duration = htod16(0); + + + while (tlv_size_left > 0) + { + type = str_ptr[0]; + switch (type) { + case CSCAN_TLV_TYPE_CHANNEL_IE: + + if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.channel_list[0], + WL_NUMCHANNELS, &tlv_size_left)) == -1) { + WL_ERROR(("%s missing channel list\n", + __FUNCTION__)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_NPROBE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.nprobes, + sizeof(iscan->iscan_ex_params_p->params.nprobes), + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_ACTIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.active_time, + sizeof(iscan->iscan_ex_params_p->params.active_time), + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_PASSIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.passive_time, + sizeof(iscan->iscan_ex_params_p->params.passive_time), + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_HOME_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.home_time, + sizeof(iscan->iscan_ex_params_p->params.home_time), + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", + __FUNCTION__, res)); + goto exit_proc; + } + break; + case CSCAN_TLV_TYPE_STYPE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, + &iscan->iscan_ex_params_p->params.scan_type, + sizeof(iscan->iscan_ex_params_p->params.scan_type), + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", + __FUNCTION__, res)); + goto exit_proc; + } + break; + + default : + WL_ERROR(("%s get unkwown type %X\n", + __FUNCTION__, type)); + goto exit_proc; + break; + } + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + +#if defined(CONFIG_FIRST_SCAN) + if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) { + if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) { + + WL_ERROR(("%s Clean up First scan flag which is %d\n", + __FUNCTION__, g_first_broadcast_scan)); + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; + } + else { + WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", + __FUNCTION__, g_first_counter_scans)); + return -EBUSY; + } + } +#endif + + + res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan); + +exit_proc: + net_os_wake_unlock(dev); + return res; +} + +#endif + + + +#ifdef SOFTAP +#ifndef AP_ONLY + + +static int +thr_wait_for_2nd_eth_dev(void *data) +{ + wl_iw_t *iw; + int ret = 0; + unsigned long flags = 0; + + tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data; + struct net_device *dev = (struct net_device *)tsk_ctl->parent; + iw = *(wl_iw_t **)netdev_priv(dev); + + DAEMONIZE("wl0_eth_wthread"); + + + WL_SOFTAP(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + if (!iw) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + tsk_ctl->thr_pid = -1; + complete(&tsk_ctl->completed); + return -1; + } + DHD_OS_WAKE_LOCK(iw->pub); + complete(&tsk_ctl->completed); + if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(5000)) != 0) { +#else + if (down_interruptible(&tsk_ctl->sema) != 0) { +#endif + WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__)); + ret = -1; + goto fail; + } + + SMP_RD_BARRIER_DEPENDS(); + if (tsk_ctl->terminated) { + ret = -1; + goto fail; + } + + flags = dhd_os_spin_lock(iw->pub); + if (!ap_net_dev) { + WL_ERROR((" ap_net_dev is null !!!")); + ret = -1; + dhd_os_spin_unlock(iw->pub, flags); + goto fail; + } + + WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n", + __FUNCTION__, ap_net_dev->name)); + + ap_cfg_running = TRUE; + + dhd_os_spin_unlock(iw->pub, flags); + bcm_mdelay(500); + + + wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK"); + +fail: + + DHD_OS_WAKE_UNLOCK(iw->pub); + + WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); + + complete_and_exit(&tsk_ctl->completed, 0); + return ret; +} +#endif +#ifndef AP_ONLY +static int last_auto_channel = 6; +#endif +static int +get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap) +{ + int chosen = 0; + wl_uint32_list_t request; + int rescan = 0; + int retry = 0; + int updown = 0; + int ret = 0; + wlc_ssid_t null_ssid; + int res = 0; +#ifndef AP_ONLY + int iolen = 0; + int mkvar_err = 0; + int bsscfg_index = 1; + char buf[WLC_IOCTL_SMLEN]; +#endif + WL_SOFTAP(("Enter %s\n", __FUNCTION__)); + +#ifndef AP_ONLY + if (ap_cfg_running) { + ap->channel = last_auto_channel; + return res; + } +#endif + memset(&null_ssid, 0, sizeof(wlc_ssid_t)); + res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); +#ifdef AP_ONLY + res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid)); +#else + iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid), + null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen); +#endif + 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")); + goto fail; + } + + 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)); + goto fail; + } + } + if ((chosen == 1) && (!rescan++)) + goto auto_channel_retry; + WL_SOFTAP(("Set auto channel = %d\n", chosen)); + ap->channel = chosen; + if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) { + WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res)); + goto fail; + } +#ifndef AP_ONLY + if (!res) + last_auto_channel = ap->channel; +#endif + +fail : + return res; +} + + +static int +set_ap_cfg(struct net_device *dev, struct ap_profile *ap) +{ + int updown = 0; + int channel = 0; + + wlc_ssid_t ap_ssid; + int max_assoc = 8; + + int res = 0; + int apsta_var = 0; +#ifndef AP_ONLY + int mpc = 0; + int iolen = 0; + int mkvar_err = 0; + int bsscfg_index = 1; + char buf[WLC_IOCTL_SMLEN]; +#endif + + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } + + net_os_wake_lock(dev); + DHD_OS_MUTEX_LOCK(&wl_softap_lock); + + 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)); + +#ifdef AP_ONLY + if (ap_cfg_running) { + wl_iw_softap_deassoc_stations(dev, NULL); + ap_cfg_running = FALSE; + } +#endif + + + if (ap_cfg_running == FALSE) { + +#ifndef AP_ONLY + + + sema_init(&ap_eth_ctl.sema, 0); + + mpc = 0; + if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) { + WL_ERROR(("%s fail to set mpc\n", __FUNCTION__)); + goto fail; + } +#endif + + updown = 0; + if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) { + WL_ERROR(("%s fail to set updown\n", __FUNCTION__)); + goto fail; + } + +#ifdef AP_ONLY + + apsta_var = 0; + if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) { + WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__)); + goto fail; + } + apsta_var = 1; + if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) { + WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__)); + goto fail; + } + 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); + if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) { + WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); + goto fail; + } + WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); +#endif + + updown = 1; + if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) { + WL_ERROR(("%s fail to set apsta \n", __FUNCTION__)); + goto fail; + } + + } else { + + if (!ap_net_dev) { + WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__)); + goto fail; + } + + res = wl_iw_softap_deassoc_stations(ap_net_dev, NULL); + + + if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { + WL_ERROR(("%s fail to set bss down\n", __FUNCTION__)); + goto fail; + } + } + + + if (strlen(ap->country_code)) { + WL_ERROR(("%s: Igonored: Country MUST be specified" + "COUNTRY command with \n", __FUNCTION__)); + } else { + WL_SOFTAP(("%s: Country code is not specified," + " will use Radio's default\n", + __FUNCTION__)); + + } + iolen = wl_bssiovar_mkbuf("closednet", + bsscfg_index, &ap->closednet, sizeof(ap->closednet)+4, + buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) { + WL_ERROR(("%s failed to set 'closednet'for apsta \n", __FUNCTION__)); + goto fail; + } + + + if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) { + ap->channel = 1; + WL_ERROR(("%s auto channel failed, pick up channel=%d\n", + __FUNCTION__, ap->channel)); + } + + channel = ap->channel; + if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) { + WL_ERROR(("%s fail to set channel\n", __FUNCTION__)); + goto fail; + } + + if (ap_cfg_running == FALSE) { + updown = 0; + if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) { + WL_ERROR(("%s fail to set up\n", __FUNCTION__)); + goto fail; + } + } + + max_assoc = ap->max_scb; + if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) { + WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__)); + goto fail; + } + + ap_ssid.SSID_len = strlen(ap->ssid); + strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); + + +#ifdef AP_ONLY + if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { + WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", + res, __FUNCTION__)); + goto fail; + } + wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START"); + ap_cfg_running = TRUE; +#else + + iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid), + ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); + ASSERT(iolen); + if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) { + WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n", + res, __FUNCTION__)); + goto fail; + } + if (ap_cfg_running == FALSE) { + + PROC_START(thr_wait_for_2nd_eth_dev, dev, &ap_eth_ctl, 0); + } else { + ap_eth_ctl.thr_pid = -1; + + if (ap_net_dev == NULL) { + WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__)); + goto fail; + } + + WL_ERROR(("%s: %s Configure security & restart AP bss \n", + __FUNCTION__, ap_net_dev->name)); + + + if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) { + WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res)); + goto fail; + } + + + if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) { + WL_ERROR(("%s fail to set bss up\n", __FUNCTION__)); + goto fail; + } + } +#endif +fail: + WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res)); + + DHD_OS_MUTEX_UNLOCK(&wl_softap_lock); + net_os_wake_unlock(dev); + + 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; +#ifdef AP_ONLY + int mpc = 0; + wlc_ssid_t ap_ssid; +#endif + wl_wsec_key_t key; + + 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) { + + + 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]; + bzero(output, 2*SHA1HashSize); + + 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)); + } + +#ifdef AP_ONLY + ap_ssid.SSID_len = strlen(ap->ssid); + strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len); + res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid)); + mpc = 0; + res |= dev_wlc_intvar_set(dev, "mpc", mpc); + if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) { + res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); + } +#endif + return res; +} + + + +static int +get_parameter_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 ((*str_ptr) && !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_ERROR((" 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); + dhd_print_buf(buf, param_max_len, 0); + } + break; + default: + + memcpy(dst, param_str_begin, parm_str_len); + *((char *)dst + parm_str_len) = 0; + WL_ERROR((" written as a string:%s\n", (char *)dst)); + 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 wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac) +{ + int i; + int res = 0; + char mac_buf[128] = {0}; + char z_mac[6] = {0, 0, 0, 0, 0, 0}; + char *sta_mac; + struct maclist *assoc_maclist = (struct maclist *) mac_buf; + bool deauth_all = false; + + + if (mac == NULL) { + deauth_all = true; + sta_mac = z_mac; + } else { + sta_mac = mac; + } + + memset(assoc_maclist, 0, sizeof(mac_buf)); + assoc_maclist->count = 8; + + res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128); + if (res != 0) { + WL_SOFTAP(("%s: Error:%d Couldn't get ASSOC List\n", __FUNCTION__, res)); + return res; + } + + if (assoc_maclist->count) + for (i = 0; i < assoc_maclist->count; i++) { + scb_val_t scbval; + scbval.val = htod32(1); + + bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN); + + if (deauth_all || (memcmp(&scbval.ea, sta_mac, ETHER_ADDR_LEN) == 0)) { + + WL_SOFTAP(("%s, deauth STA:%d \n", __FUNCTION__, i)); + res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t)); + } + } else WL_SOFTAP(("%s: No Stations \n", __FUNCTION__)); + + if (res != 0) { + WL_ERROR(("%s: Error:%d\n", __FUNCTION__, res)); + } else if (assoc_maclist->count) { + + bcm_mdelay(200); + } + return res; +} + + + +static int +iwpriv_softap_stop(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + int res = 0; + + WL_SOFTAP(("got iwpriv AP_BSS_STOP \n")); + + if ((!dev) && (!ap_net_dev)) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return res; + } + + net_os_wake_lock(dev); + DHD_OS_MUTEX_LOCK(&wl_softap_lock); + + if ((ap_cfg_running == TRUE)) { +#ifdef AP_ONLY + wl_iw_softap_deassoc_stations(dev, NULL); +#else + wl_iw_softap_deassoc_stations(ap_net_dev, NULL); + if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0) + WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res)); +#endif + + + bcm_mdelay(100); + + wrqu->data.length = 0; + ap_cfg_running = FALSE; + } else + WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__)); + + WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res)); + DHD_OS_MUTEX_UNLOCK(&wl_softap_lock); + net_os_wake_unlock(dev); + + return res; +} + + + +static int +iwpriv_fw_reload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *ext) +{ + 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_parameter_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; + + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -1; + } + + net_os_wake_lock(dev); + DHD_OS_MUTEX_LOCK(&wl_softap_lock); + + WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name)); + + +#ifndef AP_ONLY + if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) { + WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res)); + } + else { + + if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) + WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res)); + else + + bcm_mdelay(100); + } + +#endif + WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res)); + + DHD_OS_MUTEX_UNLOCK(&wl_softap_lock); + net_os_wake_unlock(dev); + + return res; +} + +static int +get_assoc_sta_list(struct net_device *dev, char *buf, int len) +{ + + WL_TRACE(("%s: dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n", + __FUNCTION__, dev, WLC_GET_ASSOCLIST, buf, len)); + + return dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len); + +} + + +void check_error(int res, const char *msg, const char *func, int line) +{ + if (res != 0) + WL_ERROR(("%s, %d function:%s, line:%d\n", msg, res, func, line)); +} + +static int +set_ap_mac_list(struct net_device *dev, void *buf) +{ + struct mac_list_set *mac_list_set = (struct mac_list_set *)buf; + struct maclist *maclist = (struct maclist *)&mac_list_set->mac_list; + int length; + int i; + int mac_mode = mac_list_set->mode; + int ioc_res = 0; + ap_macmode = mac_list_set->mode; + + + bzero(&ap_black_list, sizeof(struct mflist)); + + if (mac_mode == MACLIST_MODE_DISABLED) { + + ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); + WL_SOFTAP(("%s: MAC filtering disabled\n", __FUNCTION__)); + } else { + + scb_val_t scbval; + char mac_buf[256] = {0}; + struct maclist *assoc_maclist = (struct maclist *) mac_buf; + + + bcopy(maclist, &ap_black_list, sizeof(ap_black_list)); + + + ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode)); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); + + + length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN; + dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length); + + WL_SOFTAP(("%s: applied MAC List, mode:%d, length %d:\n", + __FUNCTION__, mac_mode, length)); + + for (i = 0; i < maclist->count; i++) + WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n", + i, maclist->ea[i].octet[0], maclist->ea[i].octet[1], + maclist->ea[i].octet[2], + maclist->ea[i].octet[3], maclist->ea[i].octet[4], + maclist->ea[i].octet[5])); + + + assoc_maclist->count = 8; + ioc_res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256); + check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__); + WL_SOFTAP((" Cur assoc clients:%d\n", assoc_maclist->count)); + + + if (assoc_maclist->count) + for (i = 0; i < assoc_maclist->count; i++) { + int j; + bool assoc_mac_matched = false; + + WL_SOFTAP(("\n Cheking assoc STA: ")); + dhd_print_buf(&assoc_maclist->ea[i], 6, 7); + WL_SOFTAP(("with the b/w list:")); + + for (j = 0; j < maclist->count; j++) + if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j], + ETHER_ADDR_LEN)) { + + assoc_mac_matched = true; + break; + } + + + if (((mac_mode == MACLIST_MODE_ALLOW) && !assoc_mac_matched) || + ((mac_mode == MACLIST_MODE_DENY) && assoc_mac_matched)) { + + WL_SOFTAP(("b-match or w-mismatch," + " do deauth/disassoc \n")); + scbval.val = htod32(1); + bcopy(&assoc_maclist->ea[i], &scbval.ea, + ETHER_ADDR_LEN); + ioc_res = dev_wlc_ioctl(dev, + WLC_SCB_DEAUTHENTICATE_FOR_REASON, + &scbval, sizeof(scb_val_t)); + check_error(ioc_res, + "ioctl ERROR:", + __FUNCTION__, __LINE__); + + } else { + WL_SOFTAP((" no b/w list hits, let it be\n")); + } + } else { + WL_SOFTAP(("No ASSOC CLIENTS\n")); + } + + } + + WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res)); + return ioc_res; +} +#endif + + + +#ifdef SOFTAP +#define PARAM_OFFSET PROFILE_OFFSET + +static 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")); + + + if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) { + WL_ERROR(("ERROR: SoftAP CFG prams !\n")); + ret = -1; + } else { + ret = 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)); + +#ifndef AP_ONLY + if (ap_net_dev == NULL) { + printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n"); + } else { + + if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0) + WL_ERROR(("%s line %d fail to set bss up\n", + __FUNCTION__, __LINE__)); + } +#else + if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0) + WL_ERROR(("%s line %d fail to set bss up\n", + __FUNCTION__, __LINE__)); +#endif + } 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")); +#ifndef AP_ONLY + if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) { + WL_ERROR(("%s line %d fail to set bss down\n", + __FUNCTION__, __LINE__)); + } +#endif + } + + return ret; + +} +#endif + + static int wl_iw_set_priv( struct net_device *dev, @@ -3756,8 +7317,6 @@ 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; @@ -3766,33 +7325,36 @@ 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\n", + dev->name, extra, info->cmd, info->flags, dwrq->length)); - if (dwrq->length && extra) { - WAKE_LOCK_INIT(iw->pub, WAKE_LOCK_PRIV, "wl_iw_set_priv"); - WAKE_LOCK(iw->pub, WAKE_LOCK_PRIV); + net_os_wake_lock(dev); - if (g_onoff == G_WLAN_SET_OFF) { + if (dwrq->length && extra) { + if (strnicmp(extra, "START", strlen("START")) == 0) { wl_iw_control_wl_on(dev, info); - if (strnicmp(extra, "START", strlen("START")) != 0) - WL_TRACE(("%s, missing START, simulate START\n", __FUNCTION__)); - else - WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); + WL_TRACE(("%s, Received regular START command\n", __FUNCTION__)); + } + + 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, "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 @@ -3806,17 +7368,62 @@ wl_iw_set_priv( ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, "STOP", strlen("STOP")) == 0) ret = wl_iw_control_wl_off(dev, info); + else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0) + ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0) + ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0) + ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) + ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) + ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0) + ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra); +#if defined(PNO_SUPPORT) + else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0) + ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) + ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) + ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); +#endif +#if defined(CSCAN) + + else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0) + ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra); +#endif +#ifdef CONFIG_MACH_MAHIMAHI + else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) + ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) + ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0) + ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra); +#else else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0) ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra); +#endif +#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 { + WL_TRACE(("Unknown PRIVATE command %s\n", extra)); snprintf(extra, MAX_WX_STRING, "OK"); dwrq->length = strlen("OK") + 1; - WL_TRACE(("Unkown PRIVATE command , ignored\n")); + WL_ERROR(("Unknown 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); @@ -3906,9 +7513,7 @@ static const iw_handler wl_iw_handler[] = (iw_handler) wl_iw_get_wpaauth, (iw_handler) wl_iw_set_encodeext, (iw_handler) wl_iw_get_encodeext, -#ifdef BCMWPA2 - (iw_handler) NULL, -#endif + (iw_handler) wl_iw_set_pmksa, #endif }; @@ -3927,11 +7532,48 @@ 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, + NULL, + (iw_handler)iwpriv_set_ap_sta_disassoc, +#endif +#if defined(CSCAN) + + NULL, + (iw_handler)iwpriv_set_cscan +#endif }; -static const struct iw_priv_args wl_iw_priv_args[] = { - { +static const struct iw_priv_args wl_iw_priv_args[] = +{ + { WL_IW_SET_ACTIVE_SCAN, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, @@ -3972,8 +7614,68 @@ 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 +#if defined(CSCAN) + { + WL_COMBO_SCAN, + IW_PRIV_TYPE_CHAR | 1024, + 0, + "CSCAN" + }, +#endif + }; const struct iw_handler_def wl_iw_handler_def = { @@ -3990,6 +7692,8 @@ const struct iw_handler_def wl_iw_handler_def = }; #endif + + int wl_iw_ioctl( struct net_device *dev, @@ -4001,12 +7705,19 @@ wl_iw_ioctl( struct iw_request_info info; iw_handler handler; char *extra = NULL; - int token_size = 1, max_tokens = 0, ret = 0; + size_t token_size = 1; + int max_tokens = 0, ret = 0; + + net_os_wake_lock(dev); + WL_TRACE(("\n%s, cmd:%x called 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)); + net_os_wake_unlock(dev); + return -EOPNOTSUPP; + } switch (cmd) { @@ -4023,11 +7734,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: @@ -4056,21 +7768,31 @@ 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) - return -E2BIG; - - if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) - return -ENOMEM; + 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)); + ret = -E2BIG; + goto wl_iw_ioctl_done; + } + if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) { + ret = -ENOMEM; + goto wl_iw_ioctl_done; + } if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { kfree(extra); - return -EFAULT; + ret = -EFAULT; + goto wl_iw_ioctl_done; } } @@ -4082,17 +7804,22 @@ wl_iw_ioctl( if (extra) { if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { kfree(extra); - return -EFAULT; + ret = -EFAULT; + goto wl_iw_ioctl_done; } kfree(extra); } +wl_iw_ioctl_done: + + net_os_wake_unlock(dev); + return ret; } -bool +static bool wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, char* stringBuf, uint buflen) { @@ -4105,7 +7832,7 @@ wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, } conn_fail_event_map_t; -# define WL_IW_DONT_CARE 9999 +#define WL_IW_DONT_CARE 9999 const conn_fail_event_map_t event_map [] = { @@ -4203,12 +7930,55 @@ 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); - + uint32 toto; + static uint32 roam_no_success = 0; + static bool roam_no_success_send = FALSE; memset(&wrqu, 0, sizeof(wrqu)); memset(extra, 0, sizeof(extra)); + if (!dev) { + WL_ERROR(("%s: dev is null\n", __FUNCTION__)); + return; + } + + net_os_wake_lock(dev); + + WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type)); + switch (event_type) { +#if defined(SOFTAP) + case WLC_E_PRUNE: + if (ap_cfg_running) { + 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); @@ -4218,12 +7988,47 @@ 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_cfg_running) { + wl_iw_send_priv_event(priv_dev, "STA_JOIN"); + goto wl_iw_event_end; + } +#endif memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; cmd = IWEVREGISTERED; break; + case WLC_E_ROAM: + if (status != WLC_E_STATUS_SUCCESS) { + roam_no_success++; + if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) { + + roam_no_success_send = TRUE; + bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); + bzero(&extra, ETHER_ADDR_LEN); + cmd = SIOCGIWAP; + WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", + __FUNCTION__)); + } else { + WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success)); + goto wl_iw_event_end; + } + } else { + memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); + wrqu.addr.sa_family = ARPHRD_ETHER; + cmd = SIOCGIWAP; + } + break; case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: +#if defined(SOFTAP) + WL_SOFTAP(("STA disconnect received %d\n", event_type)); + if (ap_cfg_running) { + wl_iw_send_priv_event(priv_dev, "STA_LEAVE"); + goto wl_iw_event_end; + } +#endif cmd = SIOCGIWAP; bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; @@ -4235,8 +8040,24 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) if (!(flags & WLC_EVENT_MSG_LINK)) { +#ifdef SOFTAP +#ifdef AP_ONLY + if (ap_cfg_running) { +#else + if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { +#endif + + WL_SOFTAP(("AP DOWN %d\n", event_type)); + wl_iw_send_priv_event(priv_dev, "AP_DOWN"); + } else { + WL_TRACE(("STA_Link Down\n")); 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); } @@ -4244,11 +8065,29 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); g_ss_cache_ctrl.m_link_down = 0; - memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN); +#ifdef SOFTAP + +#ifdef AP_ONLY + if (ap_cfg_running) { +#else + if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) { +#endif + + WL_SOFTAP(("AP UP %d\n", event_type)); + wl_iw_send_priv_event(priv_dev, "AP_UP"); + } else { + WL_TRACE(("STA_LINK_UP\n")); + roam_no_success_send = FALSE; + roam_no_success = 0; + } +#else +#endif WL_TRACE(("Link UP\n")); + } + net_os_wake_lock_timeout_enable(dev); wrqu.addr.sa_family = ARPHRD_ETHER; break; case WLC_E_ACTION_FRAME: @@ -4263,11 +8102,13 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) case WLC_E_ACTION_FRAME_COMPLETE: cmd = IWEVCUSTOM; + memcpy(&toto, data, 4); if (sizeof(status) + 1 <= sizeof(extra)) { wrqu.data.length = sizeof(status) + 1; extra[0] = WLC_E_ACTION_FRAME_COMPLETE; memcpy(&extra[1], &status, sizeof(status)); - WL_TRACE(("wl_iw_event status %d \n", status)); + printf("wl_iw_event status %d PacketId %d \n", status, toto); + printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length); } break; #endif @@ -4285,59 +8126,85 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; } -#ifdef BCMWPA2 case WLC_E_PMKID_CACHE: { - struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; - pmkid_cand_list_t *pmkcandlist; - pmkid_cand_t *pmkidcand; - int count; - - if (data == NULL) - break; - - cmd = IWEVPMKIDCAND; - pmkcandlist = data; - count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); - wrqu.data.length = sizeof(struct iw_pmkid_cand); - pmkidcand = pmkcandlist->pmkid_cand; - while (count) { - bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); - if (pmkidcand->preauth) - iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; - bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, - ETHER_ADDR_LEN); + if (data) + { + struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; + pmkid_cand_list_t *pmkcandlist; + pmkid_cand_t *pmkidcand; + int count; + + cmd = IWEVPMKIDCAND; + pmkcandlist = data; + count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); + ASSERT(count >= 0); + wrqu.data.length = sizeof(struct iw_pmkid_cand); + pmkidcand = pmkcandlist->pmkid_cand; + while (count) { + bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); + if (pmkidcand->preauth) + iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; + bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, + ETHER_ADDR_LEN); #ifndef SANDGATE2G - wireless_send_event(dev, cmd, &wrqu, extra); + wireless_send_event(dev, cmd, &wrqu, extra); #endif - pmkidcand++; - count--; + pmkidcand++; + count--; + } } - break; + goto wl_iw_event_end; } #endif -#endif case WLC_E_SCAN_COMPLETE: #if defined(WL_IW_USE_ISCAN) - if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && + if ((g_iscan) && (g_iscan->tsk_ctl.thr_pid >= 0) && (g_iscan->iscan_state != ISCAN_STATE_IDLE)) - up(&g_iscan->sysioc_sem); -#else - cmd = SIOCGIWSCAN; + { + up(&g_iscan->tsk_ctl.sema); + } else { cmd = SIOCGIWSCAN; wrqu.data.length = strlen(extra); - WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); + WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", + g_iscan->iscan_state)); + } +#else + cmd = SIOCGIWSCAN; + wrqu.data.length = strlen(extra); + WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); #endif break; + + case WLC_E_PFN_NET_FOUND: + { + wl_pfn_net_info_t *netinfo; + netinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) - + sizeof(wl_pfn_net_info_t)); + WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", + __FUNCTION__, PNO_EVENT_UP, netinfo->pfnsubnet.SSID, + netinfo->pfnsubnet.SSID_len)); + net_os_wake_lock_timeout_enable(dev); + cmd = IWEVCUSTOM; + memset(&wrqu, 0, sizeof(wrqu)); + strcpy(extra, PNO_EVENT_UP); + wrqu.data.length = strlen(extra); + } + break; + default: WL_TRACE(("Unknown Event %d: ignoring\n", event_type)); break; } #ifndef SANDGATE2G - if (cmd) - wireless_send_event(dev, cmd, &wrqu, extra); + if (cmd) { + if (cmd == SIOCGIWSCAN) + wireless_send_event(dev, cmd, &wrqu, NULL); + else + wireless_send_event(dev, cmd, &wrqu, extra); + } #endif #if WIRELESS_EXT > 14 @@ -4352,10 +8219,15 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) } #endif + goto wl_iw_event_end; +wl_iw_event_end: + + net_os_wake_unlock(dev); #endif } -int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) +int +wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) { int res = 0; wl_cnt_t cnt; @@ -4368,14 +8240,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; + bzero(&scb_val, sizeof(scb_val_t)); 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) @@ -4399,13 +8271,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; } @@ -4438,30 +8310,41 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat done: return res; } - #if defined(COEX_DHCP) static void wl_iw_bt_flag_set( struct net_device *dev, bool set) { +#if defined(BT_DHCP_USE_FLAGS) char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_lock(); #endif + +#if defined(BT_DHCP_eSCO_FIX) + + set_btc_esco_params(dev, set); +#endif + + +#if defined(BT_DHCP_USE_FLAGS) + WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set)); if (set == TRUE) { - dev_wlc_bufvar_set(dev, "btc_flags", \ - (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on)); + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on)); } else { - dev_wlc_bufvar_set(dev, "btc_flags", \ - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); } +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) rtnl_unlock(); @@ -4475,61 +8358,91 @@ wl_iw_bt_timerfunc(ulong data) bt_local->timer_on = 0; WL_TRACE(("%s\n", __FUNCTION__)); - up(&bt_local->bt_sem); + up(&bt_local->tsk_ctl.sema); } static int _bt_dhcp_sysioc_thread(void *data) { + tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data; + DAEMONIZE("dhcp_sysioc"); - while (down_interruptible(&g_bt->bt_sem) == 0) { + complete(&tsk_ctl->completed); + + while (down_interruptible(&tsk_ctl->sema) == 0) { + + SMP_RD_BARRIER_DEPENDS(); + if (tsk_ctl->terminated) { + break; + } + 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: + WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__)); 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_TIME*HZ/1000); g_bt->timer_on = 1; break; + case BT_DHCP_OPPORTUNITY_WINDOW: + if (g_bt->dhcp_done) { + WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n", + __FUNCTION__)); + goto btc_coex_idle; + } + + + WL_TRACE_COEX(("%s DHCP T1:%d expired\n", + __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME)); - WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \ - __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM)); if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE); g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); g_bt->timer_on = 1; break; + case BT_DHCP_FLAG_FORCE_TIMEOUT: - - WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \ + if (g_bt->dhcp_done) { + WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n", + __FUNCTION__)); + } else { + + WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n", __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME)); + } + if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE); + btc_coex_idle: g_bt->bt_state = BT_DHCP_IDLE; g_bt->timer_on = 0; break; + default: - WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \ + WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, g_bt->bt_state)); if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE); g_bt->bt_state = BT_DHCP_IDLE; g_bt->timer_on = 0; break; } + + net_os_wake_unlock(g_bt->dev); } if (g_bt->timer_on) { - del_timer(&g_bt->timer); g_bt->timer_on = 0; + del_timer_sync(&g_bt->timer); } - complete_and_exit(&g_bt->bt_exited, 0); + complete_and_exit(&tsk_ctl->completed, 0); } static void @@ -4541,9 +8454,8 @@ wl_iw_bt_release(void) return; } - if (bt_local->bt_pid >= 0) { - KILL_PROC(bt_local->bt_pid, SIGTERM); - wait_for_completion(&bt_local->bt_exited); + if (bt_local->tsk_ctl.thr_pid >= 0) { + PROC_STOP(&bt_local->tsk_ctl); } kfree(bt_local); g_bt = NULL; @@ -4559,7 +8471,7 @@ wl_iw_bt_init(struct net_device *dev) return -ENOMEM; memset(bt_dhcp, 0, sizeof(bt_info_t)); - bt_dhcp->bt_pid = -1; + g_bt = bt_dhcp; bt_dhcp->dev = dev; bt_dhcp->bt_state = BT_DHCP_IDLE; @@ -4569,38 +8481,69 @@ wl_iw_bt_init(struct net_device *dev) init_timer(&bt_dhcp->timer); bt_dhcp->timer.data = (ulong)bt_dhcp; bt_dhcp->timer.function = wl_iw_bt_timerfunc; + bt_dhcp->ts_dhcp_start = 0; + bt_dhcp->ts_dhcp_ok = 0; - sema_init(&bt_dhcp->bt_sem, 0); - init_completion(&bt_dhcp->bt_exited); - bt_dhcp->bt_pid = kernel_thread(_bt_dhcp_sysioc_thread, bt_dhcp, 0); - if (bt_dhcp->bt_pid < 0) { + PROC_START(_bt_dhcp_sysioc_thread, bt_dhcp, &bt_dhcp->tsk_ctl, 0); + if (bt_dhcp->tsk_ctl.thr_pid < 0) { WL_ERROR(("Failed in %s\n", __FUNCTION__)); return -ENOMEM; } return 0; } - #endif -int wl_iw_attach(struct net_device *dev, void * dhdp) + +int +wl_iw_attach(struct net_device *dev, void * dhdp) { +#if defined(WL_IW_USE_ISCAN) + int params_size = 0; +#endif wl_iw_t *iw; #if defined(WL_IW_USE_ISCAN) iscan_info_t *iscan = NULL; +#endif + + DHD_OS_MUTEX_INIT(&wl_cache_lock); + DHD_OS_MUTEX_INIT(&wl_start_lock); + DHD_OS_MUTEX_INIT(&wl_softap_lock); +#if defined(WL_IW_USE_ISCAN) if (!dev) return 0; + + memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t)); + + +#ifdef CSCAN + params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); +#else + params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); +#endif iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); if (!iscan) return -ENOMEM; memset(iscan, 0, sizeof(iscan_info_t)); - iscan->sysioc_pid = -1; + + + iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + if (!iscan->iscan_ex_params_p) + return -ENOMEM; + iscan->iscan_ex_param_size = params_size; + g_iscan = iscan; iscan->dev = dev; iscan->iscan_state = ISCAN_STATE_IDLE; + +#if defined(CONFIG_FIRST_SCAN) + g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE; + g_first_counter_scans = 0; g_iscan->scan_flag = 0; +#endif iscan->timer_ms = 3000; @@ -4608,16 +8551,16 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) iscan->timer.data = (ulong)iscan; iscan->timer.function = wl_iw_timerfunc; - sema_init(&iscan->sysioc_sem, 0); - init_completion(&iscan->sysioc_exited); - iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); - if (iscan->sysioc_pid < 0) + PROC_START(_iscan_sysioc_thread, iscan, &iscan->tsk_ctl, 0); + if (iscan->tsk_ctl.thr_pid < 0) return -ENOMEM; #endif iw = *(wl_iw_t **)netdev_priv(dev); iw->pub = (dhd_pub_t *)dhdp; - +#ifdef SOFTAP + priv_dev = dev; +#endif g_scan = NULL; @@ -4628,17 +8571,21 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) memset(g_scan, 0, G_SCAN_RESULTS); g_scan_specified_ssid = 0; +#if !defined(CSCAN) wl_iw_init_ss_cache_ctrl(); +#endif #ifdef COEX_DHCP wl_iw_bt_init(dev); #endif + return 0; } -void wl_iw_detach(void) +void +wl_iw_detach(void) { #if defined(WL_IW_USE_ISCAN) iscan_buf_t *buf; @@ -4646,26 +8593,38 @@ void wl_iw_detach(void) if (!iscan) return; - if (iscan->sysioc_pid >= 0) { - KILL_PROC(iscan->sysioc_pid, SIGTERM); - wait_for_completion(&iscan->sysioc_exited); + if (iscan->tsk_ctl.thr_pid >= 0) { + PROC_STOP(&iscan->tsk_ctl); } - + DHD_OS_MUTEX_LOCK(&wl_cache_lock); while (iscan->list_hdr) { buf = iscan->list_hdr->next; kfree(iscan->list_hdr); iscan->list_hdr = buf; } + kfree(iscan->iscan_ex_params_p); kfree(iscan); g_iscan = NULL; + DHD_OS_MUTEX_UNLOCK(&wl_cache_lock); #endif if (g_scan) kfree(g_scan); g_scan = NULL; +#if !defined(CSCAN) wl_iw_release_ss_cache_ctrl(); +#endif #ifdef COEX_DHCP wl_iw_bt_release(); #endif + +#ifdef SOFTAP + if (ap_cfg_running) { + WL_TRACE(("\n%s AP is going down\n", __FUNCTION__)); + + wl_iw_send_priv_event(priv_dev, "AP_DOWN"); + } +#endif + } diff --git a/src/wl/sys/wl_iw.h b/src/wl/sys/wl_iw.h index 1de2241..35a5033 100644 --- a/src/wl/sys/wl_iw.h +++ b/src/wl/sys/wl_iw.h @@ -1,7 +1,7 @@ /* * Linux Wireless Extensions support * - * Copyright (C) 1999-2009, Broadcom Corporation + * Copyright (C) 1999-2011, 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.20.9 2009/09/30 05:12:26 Exp $ + * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 Exp $ */ @@ -34,6 +34,43 @@ #include <proto/ethernet.h> #include <wlioctl.h> +#define WL_SCAN_PARAMS_SSID_MAX 10 +#define GET_SSID "SSID=" +#define GET_CHANNEL "CH=" +#define GET_NPROBE "NPROBE=" +#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" +#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" +#define GET_HOME_DWELL "HOME=" +#define GET_SCAN_TYPE "TYPE=" + + +#define BAND_GET_CMD "BANDGET" +#define BAND_SET_CMD "BANDSET" +#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" +#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" +#define SETSUSPEND_CMD "SETSUSPENDOPT" +#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" + +#define PNOSETUP_SET_CMD "PNOSETUP " +#define PNOENABLE_SET_CMD "PNOFORCE" +#define PNODEBUG_SET_CMD "PNODEBUG" +#define TXPOWER_SET_CMD "TXPOWER" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + + +typedef struct wl_iw_extra_params { + int target_channel; +} wl_iw_extra_params_t; + +struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int32 custom_locale_rev; +}; +#define SOFTAP 1 + #define WL_IW_RSSI_MINVAL -200 #define WL_IW_RSSI_NO_SIGNAL -91 @@ -44,7 +81,6 @@ #define WL_IW_RSSI_EXCELLENT -57 #define WL_IW_RSSI_INVALID 0 #define MAX_WX_STRING 80 -#define SSID_FMT_BUF_LEN ((4 * 32) + 1) #define isprint(c) bcm_isprint(c) #define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) #define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) @@ -54,11 +90,28 @@ #define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) #define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) -#define G_SCAN_RESULTS 8*1024 + +#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_STA_DISASSOC (SIOCIWFIRSTPRIV+29) +#define WL_COMBO_SCAN (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]; @@ -66,8 +119,10 @@ typedef struct wl_iw { struct iw_statistics wstats; int spy_num; - uint32 pwsec; - uint32 gwsec; + int wpaversion; + int pcipher; + int gcipher; + int privacy_invoked; struct ether_addr spy_addr[IW_MAX_SPY]; struct iw_quality spy_qual[IW_MAX_SPY]; @@ -75,27 +130,19 @@ typedef struct wl_iw { dhd_pub_t * pub; } wl_iw_t; -struct wl_ctrl { - struct timer_list *timer; - struct net_device *dev; - long sysioc_pid; - struct semaphore timer_sem; - struct completion sysioc_exited; -}; - -#define WLC_IW_SS_CACHE_MAXLEN 512 +int wl_control_wl_start(struct net_device *dev); +#define WLC_IW_SS_CACHE_MAXLEN 2048 #define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32 #define WLC_IW_BSS_INFO_MAXLEN \ (WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN) -typedef struct wl_iw_ss_cache{ +typedef struct wl_iw_ss_cache { + struct wl_iw_ss_cache *next; + int dirty; uint32 buflen; uint32 version; uint32 count; wl_bss_info_t bss_info[1]; - char dummy[WLC_IW_BSS_INFO_MAXLEN - sizeof(wl_bss_info_t)]; - int dirty; - struct wl_iw_ss_cache *next; } wl_iw_ss_cache_t; typedef struct wl_iw_ss_cache_ctrl { @@ -108,6 +155,42 @@ typedef struct wl_iw_ss_cache_ctrl { 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; + uint32 closednet; + char country_code[WLC_CNTRY_BUF_SZ]; +}; + + +#define MACLIST_MODE_DISABLED 0 +#define MACLIST_MODE_DENY 1 +#define MACLIST_MODE_ALLOW 2 +struct mflist { + uint count; + struct ether_addr ea[16]; +}; +struct mac_list_set { + uint32 mode; + struct mflist mac_list; +}; +#endif + #if WIRELESS_EXT > 12 #include <net/iw_handler.h> extern const struct iw_handler_def wl_iw_handler_def; @@ -119,6 +202,17 @@ extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics int wl_iw_attach(struct net_device *dev, void * dhdp); void wl_iw_detach(void); +extern int net_os_wake_lock(struct net_device *dev); +extern int net_os_wake_unlock(struct net_device *dev); +extern int net_os_wake_lock_timeout(struct net_device *dev); +extern int net_os_wake_lock_timeout_enable(struct net_device *dev); +extern int net_os_set_suspend_disable(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val); +extern int net_os_set_dtim_skip(struct net_device *dev, int val); +extern int net_os_set_packet_filter(struct net_device *dev, int val); +extern int net_os_send_hang_message(struct net_device *dev); +extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ iwe_stream_add_event(info, stream, ends, iwe, extra) @@ -135,4 +229,87 @@ void wl_iw_detach(void); iwe_stream_add_point(stream, ends, iwe, extra) #endif +extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); +extern int dhd_pno_clean(dhd_pub_t *dhd); +extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, + ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_pno_get_status(dhd_pub_t *dhd); +extern int dhd_dev_pno_reset(struct net_device *dev); +extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, + int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); +extern int dhd_dev_get_pno_status(struct net_device *dev); +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); + +void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); + +#define PNO_TLV_PREFIX 'S' +#define PNO_TLV_VERSION '1' +#define PNO_TLV_SUBVERSION '2' +#define PNO_TLV_RESERVED '0' +#define PNO_TLV_TYPE_SSID_IE 'S' +#define PNO_TLV_TYPE_TIME 'T' +#define PNO_TLV_FREQ_REPEAT 'R' +#define PNO_TLV_FREQ_EXPO_MAX 'M' +#define PNO_EVENT_UP "PNO_EVENT" + +typedef struct cmd_tlv { + char prefix; + char version; + char subver; + char reserved; +} cmd_tlv_t; + + + + +typedef struct cscan_tlv { + char prefix; + char version; + char subver; + char reserved; +} cscan_tlv_t; + +#define CSCAN_COMMAND "CSCAN " +#define CSCAN_TLV_PREFIX 'S' +#define CSCAN_TLV_VERSION 1 +#define CSCAN_TLV_SUBVERSION 0 +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' +#define CSCAN_TLV_TYPE_NPROBE_IE 'N' +#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' +#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' +#define CSCAN_TLV_TYPE_HOME_IE 'H' +#define CSCAN_TLV_TYPE_STYPE_IE 'T' + +#ifdef SOFTAP_TLV_CFG + +#define SOFTAP_SET_CMD "SOFTAPSET " +#define SOFTAP_TLV_PREFIX 'A' +#define SOFTAP_TLV_VERSION '1' +#define SOFTAP_TLV_SUBVERSION '0' +#define SOFTAP_TLV_RESERVED '0' + +#define TLV_TYPE_SSID 'S' +#define TLV_TYPE_SECUR 'E' +#define TLV_TYPE_KEY 'K' +#define TLV_TYPE_CHANNEL 'C' +#endif + +extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, + int channel_num, int *bytes_left); + +extern int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, + const char token, int input_size, int *bytes_left); + +extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, + int max, int *bytes_left); + +extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max); + +extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num); + + +#define NETDEV_PRIV(dev) (*(wl_iw_t **)netdev_priv(dev)) + #endif |